| Esempio di gestione "Bottonica" in tkinter per trescon - procedura per serializzazione di icone e tooltip associati Codice supporto : risorse.py icone utilizzate nella applicazione CODICE # -*- coding: utf-8 -*-
icoadddir = ''' iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAAXNSR0IArs4c6QAAAAlwSFlzAAAJhAA ACYQBquJjeQAAAAd0SU1FB9sFAgwBIhOliHYAAAAGYktHRAD/AP8A/6C9p5MAAAOwSURBVBgZBcFLiJ 3lGQDg5/3+/8wZTewYDeYmaIOY1ES8LtIWRFDblOKiIBYvCxci3Rm8rFzoThFRIuomG6ltF8FNwRYEN SCtLbaFQQitlzQQTSYmThJn5py5nPN9r88TAAAAAAAAAF7xS1d47tZdt95ZlDJ/Zv4/bam96BnvOQoA AACAB174KwAAr3t5z5/35DsLv29HTr6ZR06+mX9c+EPb/97+dNhbEA88/5e/T6qfdUFCEmhSP+gvvfv 8wS0A4LC7h9cMjz3z0yctXzjp8G1HwaH5B12xZbdXP33D+JvR/XHw0Dt5zy9+JbIqEIhQSvHhsU+ymx lEIJOZHPpo6yHd/rN5w9ps+P60vz08BXf9qZdzu5zcNMnTXyx80q+Ol22sjf331CUZoaC0dN32WXcdu CWmmUAyzCsdHX/GCXH2iQQAHz88BXEkwma396PlRePVsfW1ka4EWMeXp8YmmWSSKTCoy+zFdwAAABjh KvqN0ZLRaGyyNtJKWGtAibC6vuriua+troxMpWEbmpnbaeO6M2ZfCxunaa8kiKfD7LW4HhP/6qfC/09 85fS3iyggktSMli548ne/sfv6nRJF8dEXl3mpf1z5MZsvA2DuRja2YcgjKy/s6e88cMDjD91neW0iAB BoGc6cXfLZ8XMSEWHr5G77zt7r+E0fsES8HMA2bObmrw8afr5jWz8aV5/On1NrkyiIYJoMChlkFAUN/ Ux4dMth7x973b9vfNfKTxbB5ZeuduAfv3X/nqfMlw/0KWUQkSCR6IJpIiElAuvoLh/69R3P+vk3j7r4 v2+VCFfu3G5u33aTvtBSH0km0xa6oKJDRSCTDApaEkFKtfGjXTts2rUDlKS2ptTQ0EO2JFNNYIqAoKA 2pgiUZIqCWlMX1GSKDpmptdS3JDNNswlAoCKSgoZARUWgIpDJFB0qWhaZqZepNTQSGWRSANBQkIigJh 0KJoBERV/IpC8llK4XAvRIJALQI9EDejRUDAANPbrSiQj98VPf+XLxnyIbaEE0FCJJAAiyUQqZQCIQS ER0lhbO66/aNGPz1XPURgCQKEFLApISZNAaAkFJGgoSXddzfkO/+9qtbtm3V2tNh9qIQjQqIDHoqJVE V2gNyEIgkA1d50Sc0a+MJ2vnz38/u5Fp0LFe2YRayCSC9UYXRBDJIJkWEoFpQzAIahSLF5ZXgi032Ln 3MaWFVMhChmwFIbMgZBaSiEQjmpCiVCKJRiZdurjwNgAAAAAAAAAAAACAHwA72MYv6XXC8gAAAABJRU 5ErkJggg== '''
icoaddico = ''' iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAACiklEQVR4Aa3TA4wkQRgF4NmNsbZxtm3 bVnC2bdu2bdsM1ra9OzbfdXW2k8rcdPepkjeeLy9V9Uuo5cek1z/GX+Jg9TcajTaLxQIuZrP5t0N+zx iDHMLkB2Xl5SivqEBlVRWqpFJIZTLI5HLIFQooSJRKKElUKqioWK1WAg/mhSsqK1lUyqA0SDAWUauhJ tFooKEiChOUbsmBBGMRrRZaEp0OOio2m00Y5lC2ZXVDAhKMQ/R6PfQGAwxURGEWJXtItWTbURhzyDCZ THTEYa4pizItuYZ8IHcrRGFHKA3yXTVRmNtTIZRA9gEgDHN76giloVx5FuZ9mIBFnyciR5EuDrOnX72 njlByX0mG3e2FfGk+citzMfPNcHGY3QLuoHhQsp91jwQjuiSaTberdcUHhG7L7SmNVlRWIDY2FjV2B+ B17ismr9H+TC2UlJTA2dmZH6b3lm57P+U+GhysD+8NnghY7436O2rgTvpN3GXS6URDdDxXC31uNMC01 30Nu+LmbfkFpu8r3bbG/ho4G30WR6KP4HjcUZxJOI4zSUdxLvkYLiSdxPmEU1j6fgk6nO6AKR+6GWi4 HwcT1B722OiBWU9mYfrLaVjyaQHWfV+CFT9mYPH3SZjxYQTa3aoH/+OeCNwbiKHPG/PADvZ37bO1cJ/ tDrdpbnCf4YbwxaHo/6wRRr9tiaa7aqHR/hC0PhWJztdqGno9rrnZHna4v9xNIK8LCgogk0nhweCDXz TB1G8dELnZHxKB1Y8ZDhvTmDfMVbTl5+fbrt+4XuU2zRVt79TEIAYP2+IrCAcyGSwWJycn8tzce56ns faJGqh7qgYidwcYJP9r1d0VsiVgp68h4lCQoeGZkC323/8Ef+Z3Qv4MtAEAAAAASUVORK5CYII= '''
icoannulla = ''' iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAADbUlEQVR4AY2VA3BkWRSG37bGngnHtm3 bM2WsbXucUpzi2rbDRuwX27atf/8bp6dfulP1VS6/Pn3POdUSgHFpunHDvt3be2P3118fF7R7eW1sev 99e2v3LC6WHD++L+LIkZ/9Tpyo8T1zBv+ePo0/jh7Ff8ePI+LCBchXryLx4sWqpBMnfhBnbRLrV6z44 Y1583B77lx8vGABPlu6FF+sWoUv168XiHH/2qfc+9jBAd/zf8SqVd+OK061s7vwKqV3Z82COy958JIn Jd6U+VAqEGOxJvbEGbfZs/GhszNS7OzOK4pDJkx4+i9efpcX33V0xPu8fIPjW5Td5rpAjMWa2BNn3lu yBP9wPWTixIcVxXq1+mosI5B37cInhw7h7u7deH7zZjy9ZQue27pVIMZiTez1n4nhWujkyQhSq88qio 0azYmIqVORyOfIZ2TVx46h+aGH0Pjyy8h96y1kvfEGyh9/HEWXLyOJUYbyLIPph3cPKIoNWu3uSB5Os rND9qJFKFmzBvXbtqFx506UrVuHbD5BEt81csYM6LXaYamB8O5m5afQ6dYJcTLFeXy7SspaKO3YswcV a9ciZ/FipPFdYyk2aTRCOEyQJC1TFHNzkSVxBb9+T0MD2svKEMk3tiQOlCR7RbGvJM02F+ft24eexka UvfQScm7fRpUs47ft22E0E/8lSZMVxbGSpDUX5372GZr0elRxLG/ahE5+iOnVV8dEbFSre612HsWdQi wvXIiYDRuQdeAA6tjOtRs3omD5csTwjf/le/9w5MhocaMt4hohDmK51RcXI+Ptt0Xy+sWFFIvkmV54A SWpqfh9JOoS6+IpU/KF+K8VK9BWXw+Zkd0nnjsXtSUl+IzfpF+s0aTbEnGSEP/GaiiOi0MOm6SWHVZB cf6yZTBduQI/Ji/TZMKHPCPEJNoWcbgQ5zB5+ldeQVNeHrpralB+4wZS2OrttbXI8vXFH88+C/+RqtD bIv5jdFWIzmsmVUyYSJ6JrWyhjn+0Kg6bPPksxb3mnTfqjc3FvYEazWmrYsFfi2efTFu6KNma2FerSv 5ituak0i+IIp/sWbhW3rPh5cx9W9zTtq79Kmb1kq/8F9m5/+I07WUXZ2mt1d88/qnJZDKHOJNlZD3ZQ Q6S0+QKuU4ukpNkP9lG1pKlxJHMIDrywP8Xx1KfJQFl7wAAAABJRU5ErkJggg== '''
icoaset = ''' iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAAXNSR0IArs4c6QAAAAlwSFlzAAAJhAA ACYQBquJjeQAAAAd0SU1FB9sFCQAPJyNXLxIAAAAGYktHRAD/AP8A/6C9p5MAAANASURBVBgZ1cG9q9 5nHQfg63v/fs9JoqUWq7SauNhBMdXFoo1Z6yCIgwila2cnx1BQHPwbRARXO9YX1MUWLEip+FoxaoIkw WJ6mpPTnpyT87zc98cnPWi2gjp5Xf7/PP2NH3k3z3zzx/4bZevpb734g81y+cUkw7+Vxc58+fnnnnrc f+grX39B2frSpRdy8cKTMjaqaEWbJi/+4hWLnVO9VUvJwOiMKZKWIRnUGCNpjUQtFovLzz/31OdmW4c H+0Zf+dONt0wT6Tz26HtdfOKTRmqKrdAT94xBz3DPCBJjUG32u9++euHZb//6fbOto4M9d+8eOz66Y6 oy8NrfDjWlMFAVSQmqaEiRQRUSH3z4AYcHtx3d2huzrcP9mw4P79qsjvU2yaCKgWarGJ15pneqvCMIW tH7sDpeONy7aT7/ZJ9tZbO2u7vrD6/83Bi0YqAhKBSGraAoJ6pIKPH3Bx9w8PYtH/vCp9azrdV67eWf ft/Vl77jf7U4d8H5x4z5h0n72ue/6s7h2+7Zv7WnpqaqObp77NXf/8WN198wDDQnhsSJRGyNOHf2wzb LlS9X9eLS9IFPX928ufuG9dWfuXbtuqrJGMOvXrvi1vyIhx/5EEW5L2hF4r7i9OkzuXb1yrW69L2Xr3 /2M+fPrZfrGqH3QVHKNE/29g7t3V4qESfKiYHmRCkd8zz74y9/Yr585fWPPPTQozabjX9pWKMNhjIVV QxMGBiY0NHCqAhaykiZE/qgj9LQUUXiHYV1mEJhU2zCDtZoWOJ0WGGV6CPmJDIwohcJQSt66JgQjKIG QQphjRkbDLROD3PQR2wGVQQT+iBIEXTUIMWE1SBoxSa0IqGPqDA3zK2ZFrEaNMzoGFggRULHjHIi2EE a68EkTM1czDdv3/HSb/6s90GRsCiW4UyxivsKQTHCTtHjRNHDYlrYvf4P80fPvt8nzn9c6xsJAxMGpm IdqkhYYI0ZA4tiGVoxwg76PPtr3TAfHK7y1v5RjQwSrZq5WIbgVHEXZ4rl4HQjg6UTO2FZvKfx5iYeP DXZ2z/odfbiM08cL/Ps1FRRSar3UZKamrbpMVVK0zLcE1XJkDZVwmhViUpVZUTSV9/9J3Vs2NCwiBa9 AAAAAElFTkSuQmCC '''
icocambiaico = ''' iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAADrUlEQVR4AbWVA7QjSRRA17bNsW3btm3 btm3btm3bnomddEc/d6v67O/v9eacG/ftV1UPLwH/C/ob8fhOkPtf8l1i4lyKouJyuXG7BR4PHq8Xr8 TnwydRFJTYqKpOMBhEOhIT57Y7nDx/YcBgNGIymzFbLFisVqw2Gza7HbvDgUPidOKUuFw6Ui4diYrFH 4TUJKUJhb+LXBK3viod1e9PWiwvEFEKzNy9fp7da0ezcHglpnbPzdyBJdm6sAf3b56X4ugt0rfJHwjE Fc8fVnvCkEbfZ5dfyjtfObOPse0zc2BRBW7srYPpanMUQyfsd1py70gdjq+swJzeWTm5e562fFUSs8c x4qWD87BmTK5I56pfb1g5pTlLh+fDdr0VAUvS+J51YP+8kszsUxSvx0UgECAUCsUVL+6XGc/9VmyfUj RyZm0NfA87oDxu8Rdoxf0DtRnfOi2q4iMcDscVL+idAfet5rhvt8B9JwbXraZYDpfm+bqMPFmWkufrM 2I5UBr3zeZ4bjbTubimDPMHVyEqKireHvdMi+NqUxzXmuG4IRB/Np+vxt1V33Jt9rscGvYe67u8z64e b3Np6Ks8nPUF1sNVcV5opOG42Jgl/bJw4+yuuOK53VNjudAAy6WGWK82wnC2Arc2fMTZBR8ypvnXLBr biN2rx7JoTFP610vGxs7vcmfsa5j3VcR2vLbG073V6VsnWVzx7C4pMZ6uiel8LUyXa4t9+5W7+z5k1e BPWTG5lXbaEnk4krXTu7Cz53s8mPYJpr0VMe+tpDG+VYq44imtv+Xhjmw8O16KFxcrYbhekWdXc/Dg3 OfM6/kFT+5d1ITycCShYIA1E5vwdHk+DFsqYdpVA+O28qzunzGueEDtrx/MaPsZszt+zvye37JkwM8s HfIjy4d9z8KBn7JrZVtdKg8oEolwbMsUHmxsjHFnE8wH2mLa3Yjjs8sm7BXtSyd78723Xivg9bhx2Ew 47Ra8Hiduh0VEGIyW6uKTe5dxfEUXzq7tztmNg7mwYzwH1o13CvEviZa0LEtFUWRe6vsaP1rJlpVT9f fy+0tnDgZSJPslu/QkKpYVJKV+xS1fpThBtDbTEw5tX6xLL184HcqTO0t+6fgTsRfV5yQQ8OtRa1JBQ PVieHSJE/vXoUkvng0WL160pC78s4hjpJKA2GfxOSC2x+/CabrJ6eN7uHj+tJo7d9Z8f2U05ZLLjrev Avkqog4HCIcUFI+BQwd2vkiRPFnm/2Pm/fBnw/Q3Tixj9W5FyYwAAAAASUVORK5CYII= '''
icocancico = ''' iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAACm0lEQVR4AaXSQ5QdaxQF4HrWvHH1NH5 mc/QY27M40zgZxp7Htm3brr62bdfO+W9urVVdqfa/1m5cfLXrnOIkp5bydx9Txymcfvl8XigWi+hOCi yFghiw737xxReDFGH6guDz++EPBBEMhRAKhxGORBCJRhGNxRBjiccRZ0kkkJCEcAYP7hAOBN+iYUJFU MQqSDKJJEsqhZQkXcLyliLIsAqSTiPNkskgIwl9t3NYRGMMZQ2rIMNEJJvNIpvLISdJl3CUodUZJkWU gQyjEMIWJV0cS9dwO7TaUgEUMTFdw0oogcpYT2Dx9jtDS6WSPF3D4kyVUAakLRZk7HaUy+V2ydhs+Pf jj0d3CFe2X52pEupcshim6dORdTggCEIlWbpQ2/jxME6bZrzJcVpFWD4CKepasRyRA/sQ2LwJeoIYnr FawY8YAT1d7OWkSXja0MBwTTuYAEFsK58pa8UT5t+0Eb51a+FbuQL8qFF4PXw4bITyQ4fg1YQJuP/DD /wNjlO9Ayu1ZWFzZA1fEOZfvQq+ObPgnzMb3hnTYR8yGJYJ4/Hg11/5yyIqh1lbOcxQcZ7me3fxfNw4 hBYuQHD8OAQGDYSPmj5sbm47x1CF878IE6oIs9+W+/fxsLUVnu+/R/S33xBtaEDg779x59tv9cc4Tt0 lzFA5nKRF3Wpuhl6jgfODDxCuq0OkthZu+tugUuHKN9/oDxCuCHc03xQt73JTE+7qdHj68ccwE3pZp2 u7pNHoLYQ+p9fu0e8zX3+t3y3D/6dnuEyNBaVEjEbhbEODcEWtxl1CT+t0/E6a6S5CTqpU+vt0F9fov WM6nX6XDFZTBnWW3zhuzEG12nhYq+W3SBa1lb57sK5Of4jab2VOb84GevgpKoXX1Rsk6Bt2BH2zvcb1 9wAAAABJRU5ErkJggg== '''
icocset = ''' iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAEmUlEQVR4Aa2SA3AkWxSGb0+PETuLyWz WiLG2bdu2FdtZm7G1tm3btvm/s4OqrrzSw1/19dW536AP8/LyYv9n9tSXGyYLmRML9LbXJrnLLyVVZU j8lyQRyW6yi3GeFmXPNGGGJLorrhZMGvz7dGomzqRl/StOp2SiaNqI34lusmvMlMSaPHaHR2F7QAC2L 1z4LwnAoeSlSKwpBjMlin5Gyay5KJw61cCUKcidOBGFkyYZ90pB53RmqKG5aW9PRDQiq4qM4p3gQisz 5Iweh6zhw5E1dCjSRozA5evXkR8WhoxBg5A1bJj+TA/NM4YMQX5oKK7cuIFUqqU7+v1t8xYiuApvFAd AtKAiQ2rfgdjUqxc29euH+48eAZQvP38ic8ECbOzaVX9G6OeZc+fi848fAOXhkyfY3L8/NvXsicLJ0z C/kukbDwQ/i8Tr2nXEqjZtsLxpU1zMzYUpX3/9Qsr06VjZvLmeFPrJ9IEw5VJBAVbQnVWtWyN7+CjM1 DGjeOhByRQSL6vfGEvq1cPiunWR4OGBs2lpEMrXjx6NdfSzhdLzmZn6WrqjJ613P0wqT+IfIHHvzdJx FRgS3TwR7+ZmoFYtRLq64tSGDTDlG/30r4QpZ1JSEEE1cVQbT0RXqYKsgYMx2pnEEeAY67ZGNqKCCFE urghzcdETTkRotQiztcXJ5ctROsdXrcJCa2sEOzoiXKfD5j59sLpdO4Q6OmMkudiUVzxjnRPlg3Ucgq 1sscDGBoFEOBFH0gQzM2TTyyydjFGjsKphQyxr1AhJvr6YwBimEjOIIToebPAGCX3jIGVfnQQBGnMEW FggzskJyytVwsZq1ZBPrfYTf4t+b32HDphLounENOM4k+irJfHQVRKm7hGg6l5eijBLG8Ta2yPZ3BxL qCCbLn4XyK5GR+MS9bVQvql7d8wrJe5Wloe6Z5KM2Xeeo27jzCOEcYgRifTSvM6d8U0gvZecjGLazyd uxsXBlB/EBurrOUb5LKIduWx6zJGzsh0mmDd1FCGWibBYLMZ6jQZfBdLHJD1EF44qlTigUGArzW8J5L +IMJUKM43iFo48tD0mKZiu41iLuvYckjkeK0mcyvPY5+kJCp4uXowzVHyFLl5Sq3GOOGyU34yPN7xI6 uNwxjCX4/TihvYiVO00Xsmqd55g6WXLYRmJ10kkyJHJsJ3G09Sj56nwNv2CR9QdD4ibNCc5DpK8kM7y qSVXkDCWvsxCGukvgb8Nh+odx6qZR9fpFrWsGNZKxdggkSJXKsceuQKnlCpcV2vwjLrlvbkF3ppZ4KH GDJdUGhyls+1UkyGVYZVYgjgSB5B4AYm9rDl4D5ivZA02f+arW0mezXLif+8tI8EZrRS3XOV4VlmBzz VVgIca8NYAnjS6qfC+uhKPK8txRSfDMeqmHc5iZNqJsJKEI6y53zWtpU+YKW6uugaVLKQvtGqG8kQ5A WWVAgT7WgEuf1AxVLIQP3XTlfPXS2v5+enH+lM3SvzaD7bzadnTyVeAX6uejr6t+xho0dfBv2Vfhzqt +9j7telr70/jH+q2GWDn12mMVZeSbyK9s04d9hdFf85lf9K9GAAAAABJRU5ErkJggg== '''
iconset = ''' iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAFYElEQVR4AY2UA3Rc2x7GT+0+1lip21U 3qoKHa9/Ytu1kXoOJdWPbdia2bdu4tdvv7andzlrbe//++uZQAL6krfhzZohrcqCR3t9SntpUGJ3X05 jnubQ4x/KxN58BUium2xK+bs12mm7KckVHUSCqEmxQmWiNzmJ/1CZZP61Nc+gaasn+5xeDl2vctjelG DdWRuqih0HHbFMgBkrc0FvshsWuWOSnBIBuYwlvez3UxOjdHiy2O/9Z8HiFw8naOL1btQkm+OMbDgit X4sUB2UMlntjqSsBC61hSEyIA4PBAM3KEhM1vqiJN3pYn2W1/6PgkTI6a0WkzsO2DBqGkhwQfvAgzFa uhO7lU888nSfQkUpvDFSHIS0+GAkhtljqjMJgkQOKQtQmPggeqnDdywgzelCZn4C57mQsdkYjQp0Psc dYkOllgLnmUAxWeGGxIwKLbRFY7o4ixmLIfjDGqj3Rle+IsnAt+lvgxWaPDcXhestFmQno7m5HdUUB2 vLcMVLlg4X2KMw2BmKo3J3MQ7DYGorlriiSlkhMNgRjutEfiz1xGCx1Qoan9F0Bilr1Clwbp9tZE6OD vhYGamvKsbAwj8TYkGfezNZ7oa+IjoUmb8yR+WJbAJY6wjDREIjxKlcUB25CCn0j2tLNUBKqitwA5V3 PoO2ZJpJlYeqI83HGicNy+Pe/pNE/MEDgC0gMtUZv/v8wW+eG2RoXLDQSr5v+IJF4YrI+GPPtwWhI3I me9O2oTzZGZYQ6AmhCUpSAALWqKFhloif3Gn78xRM8totYdUwOWgp8yMvLQ011NSoSLDFT5YT5BjfMk TZYYI1RAl7oTsFMYzhKojXBCFPFSLEtigOUYSjBJULVRBkcIN6Sy9fgZqyGf3wdgeNXpeCs8xMU+K/A Qk8FFiqKKAzVJ1BX9DNoBEDHfNvz/A6WeGCo2AEjRbbozbYAw1cB37EfOEmVRuvylgQroyFOF82pRsj zlke8s8T9DG+lm5HWgjBR+BrSX3PBxcwY15S+etiYbIjZ5iBMVHqgv9AJQyXOGCaGerOsUBejjRAa39 2T27ZtpoqD1MSzPCTRkGJEwGZIdZN4snfH1u8pijqX4yN/pyxCAyoiVx78wsF63cXC7ImxzH87Rsscw cN9Gf/hYkNnngN6iKddaabI8pSC1Penosjb1VSoFd/VLE8Z9BXaoihACVZKPHXkYC1pa/KDlMdKSZUr 4wyWDu3bRhflvToa5aJ2vT3VBBcunMdXX30FHs6T6Eo3RXmoOmiKPDNHj+7dk5CQsIr6iXX3xhxvuce loWrI85HDpZPbBAh0JWmrGIHKU/l+shgm+Ruu8sJQkR2Y0O4McyiKfIUTxw7DzYifyE0J/qY/PziwYw sX8x2A9RTTbV1x1qQcb1mEWvNfJ+utAJ7tF4eq3SCKgbDZFfC6s8GF9js6SMiduXR0p5ujk8ir0F8e3 kbfPzyxZ4sSM8q3/tLk97erZ3eZ7dm+hYfpLQBK8OTJtaVh6vcKwrRwWuUgDqvvAOe3B9CZZU1CN0Nj nB4y3CSgJ8o5t3/bBmFm+gBQ74JXMEN4CWW27747so4RrHaX4acIWUlO8P54BGWRes/UU+SvAD/T759 cPXlgTOyXn+9/f+nSqS/+HrOyUmvCbYVrU51EUR6iigqi9XxSg3i6ALQEz46zbF8vuXn1am7eM6f6VI QEJn5iZd34RWBmFGcO/O1AtD3fzSxPSYTRfnkszMvSdGz3Jq3166kDzBq8uLef99zpJIXff03/EvBL+ Cqiu5P7dm3mW72a4tpCUf9gAplG37m39vyhQ+pfs7LyfRH43fy/C3y3bdu0aefL+f8B2ey4mWSPqRYA AAAASUVORK5CYII= '''
icookico = ''' iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAELUlEQVR4AeWTA5RbaR/G39rmoHbv961 tu/YoToZJtmN7pu6gbse2GdTWQW0bcVLl2byDu/bu0f7Oea7/v/uS/DcZ4DrA345vF0jmki7klygpKV lXUFCAvLy8X01+fn5L6HeFhYWYFjINHxV8BFGjCDbxZuJMOrHClJQUkpa2qceWLWm4f/8+DAYDdDodt FotNBoNHjx4gHv37uHOnTs0Lc8ePngI9/XuGLtuLGru1qD2fq11WPIwkNlkbTdRt1Y5ALJu3cYJSauT YX5kxvkr56HVaOlPfiS8desWdFpdS2QbpRifOh45p7ORfiYd6WfTkX8+3/pu+rsgH5KPWXHS6lQmJj4 Oc5PngJfJQ3JFMhWwrb17927LvV6nh1+aH6asnoI1R5KRdGgVVh1YhaQDSeBX8NHFp8s98gkZRdrxDP J+Y4poKj7Y9A6W7IrF2Kix2FC7AXqtnspbpAa9AcGZwXh++f+RuDsaMTvCEbMtAtHqCEjKRCASoiWfd niDlY6a59Cpj0ufxteSXkSkOgDBajlClFJMCpmItPotMBqMMBqNiMiJwAux/0fktsUIUskQ2CyDX70P 5JWe6CHpAWbh/90IZWabuONnHfuPXDxS+20V1+pTzYW0gQt5Mxd+jVxMkk9EjjIX8YXxeC6IQaBa2PJ OZnvnUeWKkDoZBssGYbZgPoL8wph9R5p/shanD4wY6j0Y4rJpEFXPhnvDbHgoZkPWMAdjhGMw1WcS5K p58FDOhqRxJnhV0xCn8MNAyQDU7KkBx1UIsdibAe4QFgBEIpL+761F72KUzAHi6k/Bq/8EAuVnEG7/F BLbvVT9DUL38xCyhwNp8yz4VS/AUPEQFCgLYDFbsGgRBwKBBwPgh+LbRCTyYnhcCTYqNmKU2A6c6hcx s3Yc5jbbohyLWYqReLe8C94o6oTpOY6w49kjR5ELzUMNzGYTOBwRqIO6WDSaq8TTU8rY/gjKkpKlGM2 xxwKFI77a2hfTdvXDtN398OX2PnCpHwv7RXbIVmTTpUdXjE1shlDoCeqgLparV9VEKvVnJBIftBNTEI sxTnYQHh2JeccHYM6JfhDvHY9hM4ciS5WNx5bHLbuT7kKLxQIPDymog7pY1OoM4u8fyvj4+OKHhOdEY OycYZDeGA35qUkY+uVgZKoyQXn8+DFMJhPd/vTaJvUDdVAXS2ZmFAkJiWZ8fQPBYkULARmBeFngCGah AzY1bwb72mptEdLW0mtf3yBQB3WxZGSsJFFRcVNCQyPw5MkT/JSawzXYcWoHfg26eWgtdVDXDzhK4uL iHeLjlx6IiIhDWFj0jxIZHosIW9hnPwmtobXUQV0/Ijo6oUti4nImPn7ZgoSEZbyEhBVtWf6TrPhR6L e0htZSx4+kH3zwAaEkJ6d1sHWnc2BgWJewsKA/FPotraG1rOvf5DsN7384pLYHSQAAAABJRU5ErkJgg g== '''
icosset = ''' iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAA CYQAAAmEBwTBV+gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAALeSURBVHjatZ XNahRBEMer5yP7lUyMQYjBgBJI1Iirou4hlyB5AR9APUsuBlSIL5B4Ex8hD+DBgwcVvHhRMXoQUVyCo Pm6iHF3vnqmp63qnWlmdkcR1GKqZ3t6+lf/rurpZVJK+B9mUbO8vPxMRPGsbdty5vhcfezguJUkCUak oKx3MabcMAz9Gy8wsb+1sx23P7z3JU6pVCufVtfWFhTYd72FTrcLzsgITM+ehNPNs/B0YxMSmQAZo4Z AoOOkUBMWL07Dq5cv4N2bjTEhBKBPasWccwjDEJJGQ00Yshksnj8GQKI1jGkgUw2gegYWOhmuULsG04 ujjkPRemDLgOqQBdoyoE4LQoGpu0hBODdzDdZRVN5Ago3gJ683gdJcZpJc9kowf2oKEqHVFsDU0WAaD KMYLsxO0mQNwk4KzFxSppRHiYA4jjW4VHGM0QMuwDSNAZmIzqBaNaflx6RWe7niSAgER/Do+dtCKvLb XWFT5ZdaczhHkmLsq/ugYrIYo3uo+NyJ6Z5M3YJOTV51IpUwYtCzouJECA3e3d2GWsPJB9OWYgmsA31 jBuzt7YBIlSaGkUtFDvL44QOt7E+NUpiZ0a/4bywvQzBWzPE/smKOqZL9dn1pCSYOT/wSwMMQ7qysQB AEqoCHxscHT7coirK+Loof+HD75i011sUDavXu2gB8dPQAGEaHCqcZRcUlYM/zIEJVgvY1BnFdt2zdw NJCE7xSqdDc3ysmEKWIwDzkZeDC+SDxXqvXAQpgBJSBeRypIzXgoUpHv3lhQGPqC2XptjXyuyLm/B4w dqM/Fd1OF77v79OBr/r9Fng+hD4VT4JlmtDBd2n1jDHTwoY+lftHj0zND48Mn8nYvu/bV65dZdkexb7 +J9GKPRfLENIzVG0Cjzid0i7V1UJ1CcK3Pn/9chkAKgRttVrQbDZnHMepVavVOhalYdt2Lc2rj+nxMJ Dbbrc/rq+vE4jldyL6j58Q3BDGwSeCEgAAAABJRU5ErkJggg== ''' setico = {"adddir" : [icoadddir, "Aggiunge le immagini di una directory al set"], "addico" : [icoaddico, "Aggiunge una singola nuova immagine al set"], "annulla" : [icoannulla, "Annulla la definizione corrente"], "aset" : [icoaset, "Apre un set di icone esistente"], "cambiaico" : [icocambiaico, "cambia, a scelta, la sola immagine o la sola descrizione di uso"], "cancico" : [icocancico, "Rimuove l'immagine corrente dal set"], "cset" : [icocset, "Chiude il programma, modifiche non salvate vengono abbandonate"], "nset" : [iconset, "Crea un nuovo set di icone"], "okico" : [icookico, "Conferma le impostazioni correnti ed aggiunge al set"], "sset" : [icosset, "Salva il set di icone corrente"] } class IcoDispencer: def __init__(self): self.icoset = setico
def getIco(self, chiave): return self.icoset[chiave][0]
def getDescr(self, chiave): try: descr = self.icoset[chiave][1] return descr except: return None
def printData(self): for chiave in self.icoset: print(chiave, ':', self.icoset[chiave][1])
def getData(self): return self.icoset > Codice di utilità : tkutilita.py - contiene classe per creare tooltip utilizzati nella applicazione CODICE #-*- coding: utf-8 -*-
''' Raccolta di classi ad utilità generale nelle applicazioni grafiche basate su tkinter raccolte in giro. Le fonti saranno indicate nelle singole classi. '''
try: import Tkinter as tk except ImportError: import tkinter as tk
class CreaToolTip(object): ''' Crea un tooltip per un generico widget.
Esempio originale tratto da stackoverflow, indirizzo: https://stackoverflow.com/questions/3221956/how-do-i-display-tooltips-in-tkinter
eseguite minime personalizzazioni. ''' def __init__(self, controllo, msg=''): self.attesa = 500 # Tempo di attesa in millisecondi self.lunghezza = 300 # dimensione del messaggio in pixel self.controllo = controllo self.testo = msg # Utilizza gli eventi del controllo chiamante self.controllo.bind('<Enter>', self.avvia) self.controllo.bind('<Leave>', self.chiudi) self.controllo.bind('<ButtonPress>', self.chiudi) self.id = None self.tw = None
def avvia(self, event=None): self.schedule()
def chiudi(self, event=None): self.unschedule() self.nasconditip()
def schedule(self): self.unschedule() self.id = self.controllo.after(self.attesa, self.mostratip)
def unschedule(self): iden = self.id self.id = None if iden: self.controllo.after_cancel(iden)
def mostratip(self, event=None): x = y = 0 x, y, cx, cy = self.controllo.bbox('insert') x += self.controllo.winfo_rootx() + 25 y += self.controllo.winfo_rooty() + 20 # crea una finestra toplevel con padre il controllo self.tw = tk.Toplevel(self.controllo) # lascia solo la label e rimuove gli elementi della finestra self.tw.wm_overrideredirect(True) self.tw.wm_geometry('+%d+%d' % (x, y)) messaggio = tk.Label(self.tw, text=self.testo, justify='left', background='#f6f6e3', relief='solid', borderwidth=1, wraplength=self.lunghezza ) messaggio.pack(ipadx=1)
def nasconditip(self): tw = self.tw self.tw = None if tw: tw.destroy() > codice per la definizione di un set di "risorse" : setcreator.pyCODICE # -*- coding: utf-8 -*-
''' Modulo di classe per la creazione di un file python (estensione *.py) per la memorizzazione dei immagini e stringhe descrittive corrispondenti, da utilizzarsi come icone in una applicazzione. '''
import os, re, base64, sys
# *** VARIABILI GLOBALI ***
idscode = ''' class IcoDispencer: def __init__(self): self.icoset = setico
def getIco(self, chiave): return self.icoset[chiave][0]
def getDescr(self, chiave): try: descr = self.icoset[chiave][1] return descr except: return None
def printData(self): for chiave in self.icoset: print(chiave, ':', self.icoset[chiave][1])
def getData(self): return self.icoset '''
# *** CLASSI ***
class IcoSetError(Exception):
def __init__(self, fonte=None, msg='Errore generico'): ''' Eccezione sollevata alla definizione di un set
Attibuti : fonte -- procedura che ha lanciato l'eccezione msg -- messaggio collegato all'errore ''' self.fonte = fonte self.msg = msg
class SetCreator: ''' Definisce i set di icone '''
def __init__(self, contesto='TK'): ''' Inizializza con un set vuoto ''' self._icoset = {} self._contesto = contesto self._dirSet = '' self._nomeSet = ''
def loadSet(self, pathset): import importlib.util, sys ''' Cerca di caricare il set di icone passato quale parametro ''' try: self._dirSet = os.path.abspath(os.path.dirname(pathset)) self._nomeSet = os.path.basename(pathset) aset = os.path.splitext(self._nomeSet)[0] spec = importlib.util.spec_from_file_location(aset, pathset) modulo = importlib.util.module_from_spec(spec) spec.loader.exec_module(modulo) ids = modulo.IcoDispencer() self._icoset = ids.getData() except ImportError: raise IcoSetError('In LoadSet, ImportError', sys.exc_info()[1]) except OSError: raise IcoSetError('In LoadSet, OSError', sys.exc_info()[1]) except ImportError: raise IcoSetError('In LoadSet, ImportError', sys.exc_info()[1]) except: raise IcoSetError('In LoadSet, errore imprevisto', sys.exc_info()[1])
def getData(self): ''' Restituisce il dizionario delle icone corrente ''' return self._icoset
def getIco(self, chiave): ''' Restituisce l'immagine della icona corrispondente alla chiave in parametro
chiave : la 'key' del dizionario in uso
restituisce : l'immagine corrispondente alla chiave o 'None' se non la trova ''' def from_tkinter(chiave): # restituzione nel caso si utilizzi tkinter try: import Tkinter as tk except: import tkinter as tk try: img = tk.PhotoImage(data = self._icoset[chiave][0]) return img except: return None
def from_gtk(chiave): # da definire, forse return None
def from_wx(chiave): # da definire, forse return None
def from_qt(chiave): # da definire, forse return None
if self._contesto == 'TK': return from_tkinter(chiave) elif self._contesto == 'GTK': return from_gtk(chiave) elif self._contesto == 'WX': return from_wx(chiave) elif self._contesto == 'QT': return from_qt(chiave) else: return None
def getDescr(self, chiave): ''' Restituisce la descrizione della icona corrispondente alla chiave in parametro
chiave : la 'key' del dizionario in uso
restituisce : la descrizione corrispondente alla chiave o 'None' se non la trova ''' try: descr = self._icoset[chiave][1] return descr except: return None
def getDir(self): ''' restituisce la directory di appartenenza del set ''' return self._dirSet
def getNomeSet(self): ''' restituisce il nome del file di set ''' return self._nomeSet
def defSet(self, dirSet, nomeSet): ''' Definisce un nuovo set di icone.
Parametri : dirSet - stringa, direttrice di storage del set nomeSet - il nome del file definente il set
Eccezioni : invoca un IconSetError in caso di parametri vuoti o di nome di file che non abbia estensione *.py. Eventuali errori di nome file causeranno errori in fase di scrittura dati. ''' # Verifica direttrice if dirSet == None or dirSet == '': raise IcoSetError('In defSet' , 'Direttrice di destinazione nulla') # verifica nome del file if nomeSet == None or nomeSet == '': raise IcoSetError('In defSet' , 'Nome del file nullo') else: elem = nomeSet.split('.') if elem[1] != 'py': raise IcoSetError('In defSet' , 'Nome del file deve essere ' + 'di tipo python (*.py)' ) self._dirSet = dirSet self._nomeSet = nomeSet
def _verfile(self, f): ext = ['png', 'gif'] nomefile = os.path.basename(f) if not nomefile.split('.')[1].lower() in ext: return False return True
def cambiaIco(self, chiave, nomeIco): ''' Cambia l'immagine corrispondente alla chiave.
Parametri : chiave, la chiave del dizionario cui riferisce l'elemento da modificare nomeIco, il path del file da inserire
Eccezioni : in caso di errori di I/O o di immagini diverse dalle tipologie "*.png" o "*.gif" viene sollevato un IcoSetError ''' # verifica esistenza chiave if not chiave in self._icoset.keys(): raise IcoSetError('In cambiaIco' , 'Chiave da variare inesistente') # verifica la compatibilità if not self._verfile(nomeIco): raise IcoSetError('In cambiaIco' , 'Tipologia immagine non supportata') # procede alla conversione dell'immagine ed assegnazione dati f = None try: f = open(nomeIco, 'rb') encIco = base64.b64encode(f.read()).decode('utf-8') self._icoset[chiave][0] = encIco except (IOError, OSError) as e: msg = "Errore I/IO : {0}".format(e) raise IcoSetError('In cambiaIco' , msg) except: msg = "Errore inatteso : " + str(sys.exc_info()[0]) raise IcoSetError('In cambiaIco' , msg) finally: if f != None: if not f.closed: f.close()
def cambiaDescr(self, chiave, descrIco): ''' Cambia la descrizione corrispondente alla chiave.
Parametri : chiave, la chiave del dizionario cui riferisce l'elemento da modificare descrIco, la descrizione da inserire, può essere vuota
Eccezioni : in caso di errori di chiave viene sollevata una IcoSetException ''' # verifica esistenza chiave if not chiave in self._icoset.keys(): raise IcoSetError('In cambiaIco' , 'Chiave da variare inesistente') p1 = re.compile('[\t\r\n]') self._icoset[chiave][1] = p1.sub('', descrIco)
def cancellaIco(self,chiave): ''' Rimuove dal set i dati corrispondenti ad una chiave
Parametri : chiave, la chiave del dizionario cui riferisce l'elemento da modificare
Eccezioni : in caso non trovi la chiave viene sollevata una IcoSetException ''' if not chiave in self._icoset.keys(): raise IcoSetError('In cancellaIco' , 'Chiave dati da eliminare inesistente' ) del self._icoset[chiave]
def addIco(self, dati): ''' Aggiunge una nuova immagine al set.
Parametri : dati - una lista contenente gli elementi : [0] - la codifica b64 della immagine [1] - la chiave della nuova immagine; [2] - eventuale descrizione, in mancanza diviene ''.
Eccezioni : in caso di errori nel file, carenza o duplicazione chiave viene sollevata un IcoSetError ''' chiave = dati[1] if chiave == None or chiave == '': raise IcoSetError('In addIco', 'Chiave non definita') if chiave in self._icoset.keys(): raise IcoSetError('In addIco' , 'Chiave già esistente') f = None self._icoset[chiave] = [dati[0], None] descr = dati[2] if descr == None: descr = '' # elimino eventuli tabulazioni e ritorni a capo p1 = re.compile('[\t\r\n]') self._icoset[chiave][1] = p1.sub('', descr)
def makeSet(self): ''' Scrive dati e metodi nel file di risorse definito, cancellando eventuali versioni già esistenti.
Eccezioni : in caso di errori di qualsiasi genere viene invocato un IcoSetError ''' fS = os.path.join(self._dirSet, self._nomeSet) f = None try: # se esiste, elimina la versione precedente if os.path.isfile(fS): os.remove(fS) # crea la nuova risorsa aprendola per scrittura f = open(fS, 'w') # *** INIZIO SCRITTURA *** testo = '# -*- coding: utf-8 -*-\n' f.write(testo) self._scriviIco(f) self._scriviDiz(f) f.write('\n\n' + idscode) except (IOError, OSError) as e: msg = 'Errore in creazione file : {0}'.format(e) raise IcoSetError('Registrazione set', msg) finally: if f != None: if not f.closed: f.close()
def _scriviIco(self, f): ''' Scrive i dati-immagine ''' for elem in sorted(self._icoset.keys()): pivot = 0 strtmp = "\nico" + elem + " = '''\n" f.write(strtmp) strDati = self._icoset[elem][0].replace('\n', '') while pivot < len(strDati): if pivot + 79 >= len(strDati): strtmp = strDati[pivot:] + '\n' else: strtmp = strDati[pivot: pivot+79] + '\n' f.write(strtmp) pivot += 79 strtmp = "'''\n" f.write(strtmp)
def _scriviDiz(self, f): ''' Scrive il dizionario di immagini e descrizioni ''' strTmp = '\nsetico = {"' spazi = '\n ' primoelem = True for elemen in sorted (self._icoset.keys()): if not primoelem: strTmp += ',\n' + spazi + '"' else: primoelem = False strTmp += (elemen + '" : [ico' + elemen + ', "' + self._icoset[elemen][1] + '"]' ) strTmp += spazi + '}' f.write(strTmp)
def _defkey(self, fn): ''' Definisce una chiave partendo da un nomefile ''' tmp = fn.split('.')[0] if tmp in self._icoset.keys(): conta = 0 vabene = False while not vabene: conta += 1 chiave = tmp + "_" + conta if not chiave in self._icoset.keys(): tmp = chiave vabene = True return tmp
def _converti(self, fi): f = None encIco = None try: f = open(fi, 'rb') encIco = base64.encodestring(f.read()).decode('utf-8') except (IOError, OSError) as e: msg = "Errore I/IO : {0}".format(e) raise IcoSetError('In converti' , msg) except: msg = "Errore inatteso : " + str(sys.exc_info()[0]) raise IcoSetError('In converti' , msg) finally: if f != None: if not f.closed: f.close() return '' + encIco
def addDirImg(self, dirimg): ''' Aggiunge le immagini compatibili presenti in una directory ''' lstfile = [f for f in os.listdir(dirimg) if os.path.isfile(os.path.join(dirimg, f))] for f in lstfile: nomefile = os.path.join(dirimg, f) if self._verfile(nomefile): newimg = [] newimg.append(self._converti(nomefile)) newimg.append(self._defkey(f)) newimg.append('') self.addIco(newimg) > interfaccia grafica della applicazione : setico.pyCODICE #!/usr/bin/env python3 # -*- coding: utf-8 -*-
tkerror = False
try: import Tkinter as tk tkerror = True except: import tkinter as tk import tkinter.ttk as ttk import tkinter.messagebox as mb import tkinter.filedialog as fd
import base64, os import risorse, setcreator
# *** VARIABILI GLOBALI *** sc = setcreator.SetCreator('TK')
# *** CLASSI *** class FRMSet(tk.Frame): ''' Pannello di definizione dei set di icone.'''
def __init__(self, master): super().__init__(master) self.master = master self.initDir = os.getenv('HOME') self.configure(pady=6) from tkutilita import CreaToolTip ids = risorse.IcoDispencer() self.lblDirSet = tk.Label(self, text='...', relief='raised', justify='left', anchor='w' ) self.lblDirSet.pack(side='top', expand=True, fill='x') lbl1 = tk.Label(self, text='Set : ') lbl1.pack(side='left') self.eSet = tk.Entry(self, width=15) self.eSet.pack(side='left', expand=True, fill='x') sep1 = tk.Frame(self, width=20) sep1.pack(side='left', fill='x') self.icoNSet = tk.PhotoImage(data = ids.getIco('nset')) self.btNSet = tk.Button(self, image=self.icoNSet, padx=6, command=self._newSet ) self.btNSet.pack(side='left', fill='x') self.btNSet_ttp = CreaToolTip(self.btNSet, ids.getDescr('nset') ) self.icoASet = tk.PhotoImage(data = ids.getIco('aset')) self.btASet = tk.Button(self, image=self.icoASet, padx=6, command=self._openSet ) self.btASet.pack(side='left', fill='x') self.btASet_ttp = CreaToolTip(self.btASet, ids.getDescr('aset') ) sep2 = tk.Frame(self, width=20) sep2.pack(side='left', fill='x') self.icoSSet = tk.PhotoImage(data = ids.getIco('sset')) self.btSSet = tk.Button(self, image=self.icoSSet, padx=4, command=self._saveSet ) self.btSSet.pack(side='left', fill='x') self.btSSet_ttp = CreaToolTip(self.btSSet, ids.getDescr('sset') ) sep3 = tk.Frame(self, width=20) sep3.pack(side='left', expand=True, fill='x') self.icoCSet = tk.PhotoImage(data = ids.getIco('cset')) self.btCSet = tk.Button(self, image=self.icoCSet, padx=4, command=master.destroy ) self.btCSet.pack(side='left', fill='x', padx=4) self.btCSet_ttp = CreaToolTip(self.btCSet, ids.getDescr('cset') )
def _newSet(self): ''' Avvia la definizione di un nuovo set di icone ''' if self.stato != 'newSet': msg = ("Avvio procedura definizione nuovo set\n\n" + "1 - scegliere direttrice;\n" + "2 - scrivere nome del set (*.py);\n" + "3 - premere nuovamente il pulsante.\n\n" + "N.B. : se già presente il set verrà\n" + " sostituito al 1° salvataggio." ) resp = mb.askyesno('Confermi operazione?', msg) #resp = mb.askyesno('Confermi operazione?', msg) if resp == False: return dirnome = fd.askdirectory(parent= self, initialdir=self.initDir, title='Selezionare direttrice' ) if not dirnome: mb.showinfo('Operazione annullata', 'Nessuna direttrice selezionata' ) return self.initDir = dirnome self.lblDirSet.configure(text=dirnome) self.setStato('newSet') else: txt = self.eSet.get() if txt != None and txt != '': if txt.split('.')[-1] != 'py': mb.showinfo('Nome set inaccettabile', 'Deve essere un file python (*.py)' ) self.eSet.focus_set() else: try: sc.defSet(self.lblDirSet.cget('text'), txt) except setcreator.IcoSetError as ie: msg = str(ie.fonte) + '\n\n' + str(ie.msg) mb.showerror("Errore definizione", msg) return self.master.setStato('in_work') else: mb.showinfo('Nome set vuoto', 'Obbligatorio, deve essere un file python (*.py)' ) self.eSet.focus_set()
def _openSet(self): ''' Permette il caricamento di un set esistente ''' fnome = fd.askopenfilename(parent=self, initialdir=self.initDir, title='Seleziona risorsa', defaultextension='.py', filetypes=[('Codice Python', '*.py') ] ) if not fnome: return # invoca il caricamento dei dati try: sc.loadSet(fnome) except setcreator.IcoSetError as ie: msg = str(ie.fonte) + '\n\n' + str(ie.msg) mb.showerror("Errore caricamento", msg) return # aggiorna i controlli di set self.lblDirSet.configure(text=sc.getDir()) self.eSet.config(state='normal') self.eSet.delete(0, tk.END) self.eSet.insert(0, sc.getNomeSet()) self.eSet.config(state='disabled') # comunica l'avvenuto caricamento self.master.gestEvento('dati_caricati')
def _saveSet(self): ''' Invoca il salvataggio dello stato corrente ''' try: sc.makeSet() self.master.setStato('in_work') except setcreator.IcoSetError as ei: msg = ei.fonte + '\n\n' + ei.msg mb.showerror("Errore cambio immagine", msg) return
def setStato(self, stato): ''' Definisce lo stato applicativo dei controlli del frame ''' self.stato = stato if self.stato == 'avvio': self.eSet.config(state='disabled') self.btNSet.config(state='normal') self.btASet.config(state='normal') self.btSSet.config(state='disabled') elif self.stato == 'newSet': self.btASet.config(state='disabled') self.eSet.config(state='normal') self.eSet.focus_set() elif self.stato == 'in_work': self.eSet.config(state='disabled') self.btNSet.config(state='disabled') self.btASet.config(state='disabled') self.btSSet.config(state='normal') elif self.stato == 'modIco' or self.stato == 'newIco': self.btSSet.config(state='disabled')
class FRMIco(tk.Frame): ''' Pannello di gestione delle singole immagini '''
def __init__(self, master): from tkutilita import CreaToolTip ids = risorse.IcoDispencer() self.initDir = os.getenv('HOME') super().__init__(master) self.master = master self._currIco = None self._nuovaIco = [] # *** Pannello rappresentazione immagine *** frmCanvas = tk.Frame(self, relief='raised', border=1) frmCanvas.pack(side='left', fill='y', padx=10, pady=10) self.canv = tk.Canvas(frmCanvas, width=120, height=120, bg='#ffffc0', relief='sunken', border=1 ) self.canv.pack(fill='both') self.didaIco = tk.Label(frmCanvas, pady=4, relief='sunken', border=1 ) self.didaIco.pack(side='bottom', fill='x') # *** Pannello bottoni di comando per immagini *** frmButton = tk.Frame(self, relief='sunken', border= 1, padx=4, pady=4) frmButton.pack(side='left', fill='y') self.icoAddIco = tk.PhotoImage(data = ids.getIco('addico')) self.btAddIco = tk.Button(frmButton, image=self.icoAddIco, padx=4, pady=4, command=self._newIco ) self.addIco_ttp = CreaToolTip(self.btAddIco, ids.getDescr('addico') ) self.btAddIco.pack() self.icoAddDir = tk.PhotoImage(data = ids.getIco('adddir')) self.btAddDir = tk.Button(frmButton, image=self.icoAddDir, padx=4, pady=4, command=self._impDir ) self.addDir_ttp = CreaToolTip(self.btAddDir, ids.getDescr('adddir') ) self.btAddDir.pack() self.icoCancIco = tk.PhotoImage(data = ids.getIco('cancico')) self.btCancIco = tk.Button(frmButton, image=self.icoCancIco, padx=4, pady=8, command=self._cancellaIco ) self.cancIco_ttp = CreaToolTip(self.btCancIco, ids.getDescr('cancico') ) self.btCancIco.pack() self.icoCambiaIco = tk.PhotoImage(data = ids.getIco('cambiaico')) self.btCambiaIco = tk.Button(frmButton, image=self.icoCambiaIco, padx=4, pady=8, command=self._variaIco ) self.cambiaIco_ttp = CreaToolTip(self.btCambiaIco, ids.getDescr('cambiaico') ) self.btCambiaIco.pack() self.icoAnnulla = tk.PhotoImage(data = ids.getIco('annulla')) self.btAnnullaIco = tk.Button(frmButton, image=self.icoAnnulla, padx=4, pady=8, command=self._annulla ) self.annullaIco_ttp = CreaToolTip(self.btAnnullaIco, ids.getDescr('annulla') ) self.btAnnullaIco.pack() self.icoOkIco = tk.PhotoImage(data = ids.getIco('okico')) self.btOkIco = tk.Button(frmButton, image=self.icoOkIco, padx=4, pady=8, command=self._salvaIco ) self.okIco_ttp = CreaToolTip(self.btOkIco, ids.getDescr('okico') ) self.btOkIco.pack(side='bottom') # *** Pannello descrittori di icona *** lfrmData = tk.LabelFrame(self, text=' Descrizione ', padx=4, pady=4) lfrmData.pack(side='left', expand=True, fill='both', padx=4, pady=4) subf1 = tk.Frame(lfrmData, padx=0, pady=0) subf1.pack(expand=True, fill='x', padx=0, pady=0) lbl1 = tk.Label(subf1, text='Nome :', width=7, justify='left') lbl1.pack(side='left', anchor='n') self.eNomeIco = tk.Entry(subf1, width=15) self.eNomeIco.pack(side='left', expand=True, fill='x', anchor='n') subf2 = tk.Frame(lfrmData) subf2.pack(expand=True, fill='both') lbl2 = tk.Label(subf2, text='Uso :', width=7, justify='left') lbl2.pack(side='left', anchor='n') self.tUsoIco = tk.Text(subf2, width=15, height=4, wrap='word') self.tUsoIco.pack(side='left', anchor='n', expand=True, fill='both') self.tScroll = tk.Scrollbar(subf2, orient=tk.VERTICAL) self.tUsoIco.config(yscrollcommand=self.tScroll.set) self.tScroll.config(command=self.tUsoIco.yview) self.tScroll.pack(side='right', anchor='n', fill='y')
def setStato(self, stato): self.stato = stato if self.stato == 'avvio': # Non c'è set corrente, tutto disabilitato self.btAddIco.config(state='disabled') self.btAddDir.config(state='disabled') self.btCancIco.config(state='disabled') self.btCambiaIco.config(state='disabled') self.btAnnullaIco.config(state='disabled') self.btOkIco.config(state='disabled') self.eNomeIco.config(state='disabled') self.tUsoIco.config(state='disabled') elif self.stato == 'in_work': # Set aperto senza elementi selezionati self.btAddIco.config(state='normal') self.btAddDir.config(state='normal') self.btCancIco.config(state='disabled') self.btCambiaIco.config(state='disabled') self.btAnnullaIco.config(state='disabled') self.btOkIco.config(state='disabled') self.eNomeIco.config(state='disabled') self.tUsoIco.config(state='disabled') elif self.stato == 'ico_selected': # Modifiche per icona selezionata self.btCancIco.config(state='normal') self.btCambiaIco.config(state='normal') elif self.stato == 'modIco': self.btAddIco.config(state='disabled') self.btAddDir.config(state='disabled') self.btCancIco.config(state='disabled') self.btCambiaIco.config(state='disabled') self.btAnnullaIco.config(state='normal') self.btOkIco.config(state='normal') self.eNomeIco.config(state='disabled') self.tUsoIco.config(state='normal') self.tUsoIco.focus_set() elif self.stato == 'newIco': self.btAddIco.config(state='disabled') self.btAddDir.config(state='disabled') self.btCancIco.config(state='disabled') self.btCambiaIco.config(state='disabled') self.btAnnullaIco.config(state='normal') self.btOkIco.config(state='normal') self.eNomeIco.config(state='normal') self.tUsoIco.config(state='normal') self.eNomeIco.focus_set()
def _cleanCtr(self): ''' Svuota i controlli icona
N,B, : I controlli di testo del frame vengono attivati e rimangono attivi, eventuale disattivazione va eseguita nel processo chiamante ''' self.canv.delete('all') self._currIco = None self.didaIco.configure(text='') # attiva i campi di testo self.eNomeIco.config(state='normal') self.tUsoIco.config(state='normal') # Pulizia e riscrittura dei campi di testo self.eNomeIco.delete(0, tk.END) self.tUsoIco.delete(1.0, tk.END)
def _convertiIco(self, nomeIco): ''' Converte un file di immagine ''' ext = ['png', 'gif', 'jpg', 'jpeg'] # verifica l'estensione del file immagine nomefile = os.path.basename(nomeIco) if not nomefile.split('.')[1].lower() in ext: raise setcreator.IcoSetError('In convertiIco' , 'Tipologia immagine non supportata' ) # procede alla conversione dell'immagine ed assegnazione dati f = None encIco = None try: f = open(nomeIco, 'rb') encIco = base64.encodestring(f.read()).decode('utf-8') except (IOError, OSError) as e: msg = "Errore I/IO : {0}".format(e) raise setcreator.IcoSetError('In convertiIco' , msg) except: msg = "Errore inatteso : " + str(sys.exc_info()[0]) raise setcreator.IcoSetError('In convertiIco' , msg) finally: if f != None: if not f.closed: f.close() return '' + encIco
def esegui(self, comando, chiave='', file=''): ''' Esegue un comando passato dalla finestra principale ''' if comando == 'mostra_icona': # mostra una icona già registrata # pulizia e ridisegno del canvas self._cleanCtr() # - calcolo coordinate di inizio e disegno self._currIco = sc.getIco(chiave) x = self.canv.winfo_width() // 2 y = self.canv.winfo_height() // 2 self.canv.create_image(x, y, image=self._currIco, anchor='center') self.didaIco.configure(text=str(self._currIco.width()) + 'x' + str(self._currIco.height())) # scrittura campi di testo self.eNomeIco.insert(0, chiave) self.tUsoIco.insert(tk.END, sc.getDescr(chiave)) # disattiva i campi di testo self.eNomeIco.config(state='disabled') self.tUsoIco.config(state='disabled') # ridefinisce lo stato del frame self.setStato('ico_selected') elif comando == 'mostra_immagine': # mostra l'immagine di una nuova icona self._cleanCtr() self._nuovaIco = [] self._nuovaIco.append(self._convertiIco(file)) self._currIco = tk.PhotoImage(data = self._nuovaIco[0]) x = self.canv.winfo_width() // 2 y = self.canv.winfo_height() // 2 self.canv.create_image(x, y, image=self._currIco, anchor='center') self.didaIco.configure(text=str(self._currIco.width()) + 'x' + str(self._currIco.height()))
def _apriImg(self): ''' Apre un file di immagine e restituisce il nomefile ''' # base per tipi di files tipi = [('Files immagine', ('*.png', '*.PNG', '*.gif', '*.GIF' ) ) ] fnome = fd.askopenfilename(parent=self, initialdir=self.initDir, title='Seleziona immagine', defaultextension='.png', filetypes=tipi ) if not fnome: return None # definisce la direttrice corrente quale predefinita if os.path.isfile(fnome): self.initDir = os.path.dirname(fnome) return fnome
def _impDir(self): ''' Importa nel set le immagini compatibili di una directory ''' initDir = os.getenv('HOME') dirnome = fd.askdirectory(parent= self, initialdir=initDir, title='Selezionare direttrice' ) if not dirnome: return try: sc.addDirImg(dirnome) except setcreator.IcoSetError as ie: msg = str(ie.fonte) + '\n\n' + str(ie.msg) mb.showerror("Errore lettura immagini", msg) return self.master.gestEvento('updateIco')
def _variaIco(self): ''' Cambia l'icona o la descrizione di un elemento ''' msg = ("Può essere variata l'immagine o la descrizione d'uso\n\n" + "Volete cambiare l'immagine?") resp = mb.askyesnocancel('Cosa cambio?', msg) if resp == None: return elif resp == True: fnome = self._apriImg() if not fnome: return try: sc.cambiaIco(self.eNomeIco.get(), fnome) except setcreator.IcoSetError as ie: msg = str(ie.fonte) + '\n\n' + str(ie.msg) mb.showerror("Errore cambio immagine", msg) return self.esegui('mostra_icona', self.eNomeIco.get()) else: self.master.setStato('modIco')
def _variaDescr(self): ''' Riassegna la descrizione d'uso dell'icona corrente ''' try: descr = self.tUsoIco.get(1.0, tk.END) if descr: sc.cambiaDescr(self.eNomeIco.get(), descr) else: sc.cambiaDescr(self.eNomeIco.get(), '') except setcreator.IcoSetError as ie: msg = str(ie.fonte) + '\n\n' + str(ie.msg) mb.showerror("Errore cambio descrizione", msg) return self.master.gestEvento('updateIco')
def _newIco(self): ''' Imposta l'ambiente per l'inserimento di una nuova icona ''' # definisce lo stato del frame e regola i controlli nf = self._apriImg() if nf == None or nf == '': # nessuna selezione, processo annullato mb.showinfo("Processo annullato", 'Nessun file è stato selezionato' ) self.master.setStato('in_work') return try: self.master.setStato('newIco') self.esegui('mostra_immagine', file=nf) except setcreator.IcoSetError as ie: msg = str(ie.fonte) + '\n\n' + str(ie.msg) mb.showerror("Errore immagine", msg) self.master.setStato('in_work') return self.eNomeIco.focus_set()
def _annulla(self): ''' Annulla la definizione corrente ''' self._cleanCtr() # disattiva i campi di testo self.eNomeIco.config(state='disabled') self.tUsoIco.config(state='disabled') self.master.gestEvento('updateIco')
def _salvaIco(self): ''' Secondo lo stato del frame aggiorna o aggiunge l'icona ''' if self.stato == 'modIco': self._variaDescr() elif self.stato == 'newIco': nomeIco = self.eNomeIco.get() if not nomeIco: msg = ('Il nome da assegnare è un dato necessario\n\n' + 'Si vuol proseguire nella immissione?') resp = mb.askyesno('Cosa vuoi fare?', msg) if resp == True: self.eNomeIco.focus_set() return else: self._clearCtr() self.master.setStato('in_work') return self._nuovaIco.append(nomeIco) descr = self.tUsoIco.get(1.0, tk.END) self._nuovaIco.append(descr) try: sc.addIco(self._nuovaIco) except setcreator.IcoSetError as er: msg = str(er.fonte) + '\n\n' + str(er.msg) mb.showerror("Errore In Aggiunta", msg) return self.master.gestEvento('updateIco') else: return
def _cancellaIco(self): ''' Cancella l'elemento corrente dal set ''' if self.eNomeIco.get() == None or self.eNomeIco.get() == '': return msg = ("Siete certi di voler eliminare l'elemento\n\n" + self.eNomeIco.get() + "?") resp = mb.askyesnocancel('Richiesta conferma', msg) if resp == None: return elif resp == True: try: sc.cancellaIco(self.eNomeIco.get()) except setcreator.IcoSetError as ie: msg = str(ie.fonte) + '\n\n' + str(ie.msg) mb.showerror("Errore cancellazione immagine", msg) return # ripulisce i controlli self._cleanCtr() # disattiva i campi di testo self.eNomeIco.config(state='disabled') self.tUsoIco.config(state='disabled') # ridefinisce lo stato del frame self.master.gestEvento('updateIco') else: return
class FRMLista(tk.Frame): ''' Pannello della lista delle immagini presenti '''
def __init__(self, master): super().__init__(master) self.stato = '' self.configure(padx=4, pady=4) lbl1 = tk.Label(self, text='Lista Immagini :') lbl1.pack(anchor='w') # test con frame per utilizzo layout "grid" frmGrid = tk.Frame(self) frmGrid.pack(expand=True, fill='both') self.tvIco = ttk.Treeview(frmGrid, columns=('chiave', 'descr'), selectmode='browse', show='headings', height=4) # definizione colonne treeview self.tvIco.heading('chiave', text='Chiave') self.tvIco.column('chiave', stretch=False, width=150) self.tvIco.heading('descr', text='Descrizione') self.tvIco.column('descr', width=150) # definizione dello scroll vScroll = tk.Scrollbar(self, orient=tk.VERTICAL) vScroll.config(command=self.tvIco.yview) self.tvIco.configure(yscrollcommand=vScroll.set) self.tvIco.grid(column=0, row=0, sticky='nsew', in_=frmGrid ) vScroll.grid(column=1, row=0, sticky='ns', in_=frmGrid ) frmGrid.grid_columnconfigure(0, weight=1) frmGrid.grid_rowconfigure(0, weight=1) # selezione dalla treeview con doppio click mouse # o pressione dei tasti 'Invio' self.tvIco.bind('<Double-1>', self._tvDbClick) self.tvIco.bind('<Return>', self._tvDbClick) self.tvIco.bind('<KP_Enter>', self._tvDbClick)
def _tvDbClick(self, event): # si legge la riga selezionata riga = self.tvIco.item(self.tvIco.focus()) # verifica vi siano dati if len(riga['values']) == 0: return # estrae la chiave dal primo dei valori associati chiave = riga['values'][0] self.master.comando('scelta_icona', chiave)
def setStato(self, stato): ''' Gestisce le condizioni contestuali del frame ''' self.stato = stato if self.stato == 'in_work': self.tvIco.state(('!disabled',)) else: self.tvIco.state(('disabled',))
def evento(self, cosa): ''' Risponde ad una segnalazione di evento dati ''' if cosa == 'dati_caricati': # ripulisce la treeview for elem in self.tvIco.get_children(): self.tvIco.delete(elem) # carica i dati disponibili for elem in sorted(sc.getData().keys()): self.tvIco.insert('', 'end', values=(elem, sc.getDescr(elem) ) ) return True
class GUISet(tk.Tk): ''' Finestra principale della applicazione. '''
def __init__(self): super().__init__() self.nascondi() self.title('Gestore Set Icone') self.option_add('*Dialog.msg.font', 'Helvetica 9') # Posiziona i frame componenti vuoti self.frmSet = FRMSet(self) self.frmSet.pack(fill='x') self.frmIco = FRMIco(self) self.frmIco.pack(fill='x') self.frmList = FRMLista(self) self.frmList.pack(expand=True, fill='both') # aggiorna i parametri della finestra self.update() # Richiede le proprie dimensioni wx = self.winfo_reqwidth() wy = self.winfo_reqheight() # e le imposta come minime per la finestra self.minsize(width=wx, height=wy) # imposta i controlli alla condizione iniziale self.setStato('avvio') # si nasconde
def nascondi(self): ''' Nasconde la finestra. Da utilizzarsi prima dell'inserimento dei componenti della finestra ''' self.withdraw()
def mostra(self): ''' Mostra la finestra ''' self.deiconify()
def setStato(self, stato=''): ''' Imposta lo stato dei controlli nei sub-frame ''' self.frmSet.setStato(stato) self.frmIco.setStato(stato) self.frmList.setStato(stato)
def gestEvento(self, evento): ''' Decide cosa comunicare ai frame sul verificarsi di una circostanza ''' if evento == 'dati_caricati': if self.frmList.evento(evento): self.setStato('in_work') elif evento == 'updateIco': self.frmSet.setStato('in_work') self.frmIco.setStato('in_work') self.frmList.evento('dati_caricati') def comando(self, comando, chiave=''): ''' Distribuisce i comandi tra i frame ''' if comando == 'scelta_icona': self.frmIco.esegui('mostra_icona', chiave)
def centraFinestra(gui): ''' Centra una finestra, passata come parametro, sullo schermo ''' l = gui.winfo_screenwidth() a = gui.winfo_screenheight() wx = gui.winfo_reqwidth() wy = gui.winfo_reqheight() gui.geometry('{}x{}+{}+{}'.format(wx, wy, (l-wx)//2, (a-wy)//2))
def main(): finestra = GUISet() centraFinestra(finestra) finestra.mostra() finestra.mainloop()
if __name__ == '__main__': if tkerror: print('Mi dispiace, questo codice non è compatibile' + ' con le versioni 2.x di python-Tkinter') else: main() >
|