Visualizza post

Questa sezione ti permette di visualizzare tutti i post inviati da questo utente. N.B: puoi vedere solo i post relativi alle aree dove hai l'accesso.


Topics - nuzzopippo

Pagine: [1]
1
I miei saluti

Nel corso dei miei tentativi di studio di alcuni pattern mi sono imbattuto in un tipo di notazione per me nuova in python, ossia la dichiarazione di tipo per parametri e return di un metodo/funzione (pep's 3107 e 484) ... devo dire che mi ha fatto piacere trovarle ma nel seguire un esempio così posto :

from abc import ABC, abstractmethod
from random import randrange
from typing import List

class Observer(ABC):
    '''
L'interfaccia di Observer dichiara il metodo di aggiornamento, utilizzato
dai subjects.
'''

    @abstractmethod
    def update(self, subject: Subject) -> None:
        '''
Riceve lo update da subject.
'''
        pass


class Subject(ABC):
    '''
Oggetto interfaccia, dichiara una serie di metodi per la gestione
di subscribers.
'''

    @abstractmethod
    def attach(self, observer: Observer) -> None:
        '''
...


Mi son reso conto che, almeno nella versione 3.6.9 di python che uso, la notazione è valida solo se il tipo di oggetto dichiarato quale parametro è definito precedentemente alla dichiarazione stessa, altrimenti si ha :

Python 3.6.9 (default, Nov  7 2019, 10:44:02)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license()" for more information.
>>>
======= RESTART: /media/nuzzopippo/progetti/mvc_example/observer_ex.py =======
Traceback (most recent call last):
  File "/media/nuzzopippo/progetti/mvc_example/observer_ex.py", line 7, in <module>
    class Observer(ABC):
  File "/media/nuzzopippo/progetti/mvc_example/observer_ex.py", line 14, in Observer
    def update(self, subject: Subject) -> None:
NameError: name 'Subject' is not defined
>>>


Problema aggirabile facilmente, omettendo la dichiarazione di tipo
======= RESTART: /media/nuzzopippo/progetti/mvc_example/observer_ex.py =======
Subject: Aggiunto un observer.
Subject: Aggiunto un observer.


metodo che però non trovo gradevole, provato a rileggere dette pep's con l'unico risultato di "incartarmi", ho capito poco e non ne sono venuto a capo (anzi ho trovato un sacco di ulteriori cose da "vedere"), anche se ho il sospetto manchi un
from __future__ import annotations

disponibile da python 3.7 e che sarà "consolidato" in python 4.0

A parte il dichiarare gli oggetti "parametro" in moduli diversi in caso di incroci, o di omettere tale dichiarazione, qualcuno conosce una metodologia più corretta per la definizione di tali parametri incrociando oggetti definiti nello stesso modulo?

2
Tkinter / Tooltip in tkinter
« il: Gennaio 06, 2020, 13:26 »
Saluti a Voi :)

Il presente post NON È una richiesta di supporto ma una "offerta" che porgo agli utenti che stanno iniziando con python e che, come constato, si avventurano a programmare GUI con tkinter.

Avendo deciso di fare, solo per sperimentare alcuni pattern (MVC-Observer), quello che sarà il mio ultimo "esperimento" con tkinter, poi passerò ad altro framework, organizzandolo "come piace a me", ossia con tutti gli "accorgimenti" che mi piace realizzare in una finestra grafica, Uno dei detti "accorgimenti" e applicare "tooltip", tanto ai vari widget, quanto ai menu, cosa che in tkinter non è possibile fare a meno di non integrare nel proprio codice l'obsoleta libreria TIX ed utilizzare il controllo aggiuntivo "balloon" ... cosa che non ho voluto fare.

Con l'aiuto di San Google e di un paio di classi, in parte personalizzate, trovare su stackoverflow, citata la fonte nella docs delle calssi che seguono, ho realizzato un sistema di tooltip utilizzabili in tkinter senza aggiungere ulteriori librerie, articolato in tre classi.

La prima "CreaToolTip" è dedicata ai widget "comuni" e si invoca chiamando "tooltip = CreaToolTip(widget, testo)", ovvio che è solo uno schema di chiamata, ove "widget" è il controllo cui deve essere applicato il tootip e "testo" è il testo da applicarsi, va da se che un toltip definito in una classe deve essere memorizzato quale variabile di istanza della classe stessa.

Le altre due classi sono dedicare a far apparire dei tooltip in un menu tkinter, applicati ai soli item "command", ed è ottenuta sub-classando la classe "Menu" di tkinter nella classe "MenuTooltip" che provvede a memorizzare indice e tooltip di un item "command" definito, quindi ad intercettare il passaggio del mouse esponendo il tooltip corrispondente all'item sottostante il puntatore. La definizione del tooltip avviene semplicemente aggiungendo un ulteriore argomento "tooltip=testo_da_mostrare" in una invocazione "menu.add_command()". Poi provvede la classe "MenuTooltip ad invocare la classe "ToolTipWin" che provvede a visalizzare effettivamente il tooltip.
Preciso che dette classi sono limitate a ciò che ritengo mi serva per lo studio per cui sono state create, potrebbero facilmente essere ridotte a due le classi necessarie ed espanse le tipologie di item servite, compito degli eventuali interessati, se vogliono.

In successione a questo post ne farò un altro per fornirvi un esempio funzionale di test, sarebbe troppo lungo per un unico post dato che una interfaccia che stavo preparando per miei scopi e durante la cui realizzazione mi è venuto il pensiero che questo argomento potrebbe interessare altri utenti del Forum.

Intanto, il codice delle classi definenti i tooltip, 202 righe ;
# -*- coding: utf-8 -*-

import tkinter as tk

# *** CLASSI DI UTILITÀ DERIVATE DA ALTRE TROVATE IN GIRO ED ADATTATE ***

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()



class MenuTooltip(tk.Menu):
    '''
    da https://stackoverflow.com/questions/55316791/how-can-i-add-a-tooltip-to-menu-item
    permette di aggiungere un tooltip ai menu-items.
    Introdotte variazioni funzionali rispetto all'esempio citato.
    '''
    def __init__(self, parent):
        """
        :parametro parent: il master del Menu, può essere 'root' o 'Menubar'
         .tooltip == Lista di tuple (yposition, text)
         .tooltip_active == Indice (0-based) del Tooltip attivo
         eventi intercettati <Leave>, <Motion>
        """
        super().__init__(parent, tearoff=0)
        self.tooltip = []
        self.tooltip_active = None
        self.tooltip_win = None

        self.bind('<Leave>', self.leave)
        self.bind('<Motion>', self.on_motion)

    def add_command(self, *cnf, **kwargs):
        tooltip = kwargs.get('tooltip')
        if tooltip:
            del kwargs['tooltip']
        super().add_command(*cnf, **kwargs)
        # chiede l'indice dell'ultimo command
        u_command = self.index("end")
        self.add_tooltip(u_command, tooltip)

    def add_tooltip(self, index, tooltip):
        """
        :parametro index  : Indice (0-based) degli item del Menu
        :parametro tooltip: Testo da mostrare quale Tooltip
        :return: None
        """
        self.tooltip.append((self.yposition(index) + 2, tooltip))

    def on_motion(self, event):
        """
        Cicla i .tooltip per trovare il Menu Item
        """
        for idx in range(len(self.tooltip) - 1, -1, -1):
            if event.y >= self.tooltip[idx][0]:
                x = event.x_root
                y = event.y_root
                point = (x, y)
                self.show_tooltip(idx, point)
                break

    def leave(self, event):
        """
        Distrugge il Tooltip corrente e resetta .tooltip_active a None
        """
        if not self.tooltip_active is None:
            # destroy(<tooltip_active>)
            if self.tooltip_win:
                self.tooltip_win.chiudi()
            self.tooltip_active = None

    def show_tooltip(self, idx, point):
        """
        Mostra il Tooltip se non presente, distrugge il Tooltip attivo
        :parametro idx: Indice del Tooltip mostrato
        :point        : coordinate di posizionamento del tooltip
        :return: None
        """
        if self.tooltip_active != idx:
            # destroy(<tooltip_active>)
            if self.tooltip_win:
                self.tooltip_win.chiudi()
            # create new tooltip
            self.tooltip_active = idx
            msg = self.tooltip[idx][1]
            self.tooltip_win = ToolTipWin(self, point, msg)
            self.tooltip_win.avvia()


# *** MIE CLASSI ***

class ToolTipWin(object):
    '''
Ricodifica della classe CreaToolTip mirata alla esposizione di tooltip
in un menu tkinter (gli oggetti items non vengono restituiti quali widget)
'''
    def __init__(self, ctrl, point, msg=''):
        self.attesa = 500
        self.lunghezza = 300
        self.ctrl = ctrl
        self.text = msg
        self.point = point
        self.id = None
        self.tw = None

    def avvia(self):
        self.unschedule()
        self.id = self.ctrl.after(self.attesa, self.mostra_tip)

    def chiudi(self):
        self.unschedule()
        self.nascondi_tip()

    def unschedule(self):
        iden = self.id
        self.id = None
        if iden:
            self.ctrl.after_cancel(iden)

    def mostra_tip(self):
        x, y = self.point
        # crea una finestra toplevel con padre il menu
        self.tw = tk.Toplevel(self.ctrl)
        # 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.text,
                            justify='left',
                            background='#f6f6e3',
                            relief='solid',
                            borderwidth=1,
                            wraplength=self.lunghezza
                            )
        messaggio.pack(ipadx=1)

    def nascondi_tip(self):
        tw = self.tw
        self.tw = None
        if tw:
            tw.destroy()

3
Tkinter / [Risolto] Elenco nomi dei colori in tkinter
« il: Dicembre 03, 2019, 18:28 »
Signori, buona sera

Mi è venuto in mente di fare una dialog di selezione colori in tkinter basata sui nomi dei colori riconosciuti da tkinter e sto facendo qualche esperimento in merito.

La prima prova che mi è venuta in mente, è di popolare la finestra con una serie di label con assegnato il colore tramite il color-name (pessima idea, tempi biblici, troverò qualche altro modo).
Pur avendo trovato i nomi dei colori nella docs in questa pagina, data la pigrizia, ho pensato bene di andarmi a leggeri i nomi dei colori nel file "rgb.txt" di X11, in fondo quei nomi in tkinter si basano su X, applicandoli alle label, ne sono stati riconosciuti 751 su 753, contro i 760 presenti nel documento citato (colori mac e windows esclusi)

Ora, è banale che quei nomi di colore siano memorizzati da qualche parte in tkinter, dato che vengono riconosciuti.
Volendo evitare di scriverli nel codice e/o in un file (che comunque possiedo) ho cercato un metodo od una variabile che li contenga, tanto nella docs quanto leggendo direttamente il sorgente python delle tkinter, non cavandone un ragno dal buco e senza schiarirmi le idee (solo il vago sospetto siano nei binari).

Conoscete un metodo per "estrarre" l'elenco dei nomi di colore o, almeno, come stanno le cose?

Grazie dell'attenzione, ciao.

4
Buon giorno, signori.

Mi son trovato a dover affrontare un cambio della modalità della rete ethernet in ambito lavorativo che, per motivi vari, è passata dalla condizione di rete ad indirizzi TCP-IP fissi, sotto il controllo del personale interno, ad un sistema DHCP con controllo eterno (oltre tutto ben poco "disponibile" a dialogo ed integrazioni) che ha causato il crollo di tutte le applicazioni localmente sviluppate, tra cui alcune estremamente critiche.
Per le applicazioni critiche ho risolto creando una sotto-rete ad IP fissi e spostando nella stessa le macchine interessate alla gestione, negando qualsiasi comunicazione esterna.

Per quanto riguarda gli aspetti di mero servizio, ho risolto sviluppando dei prototipi in python per tentare l'individuazione in rete dei server ed una volta riuscita, traducendo i metodi in java/visual basic integrandoli nelle applicazioni interessate, lasciando il funzionamento nell'ambito della rete DHCP.

In questa seconda fascia, le tipologie di server interessati sono : PostgreSQL, FTP, SSH ed HTTP.
La strategia di approccio da me "ideata" è stata, preliminarmente :
- per i database, inserita una tavola con un campo identificativo specifico della base dati ed una tavola riferente agli altri server contenente i dati identificativi ed utenza necessari;
- per i server FTP inserendo stringhe identificative nel banner degli stessi;
- per gli SSH nessuna (li uso solo io);
- per gli HTTP spostando le porte di ascolto dei vari virtual-host e costruendo un launcher java per ovviare alla riveniente inutilità dei files "hosts" (la lan locale non dispone di server DNS, che poi bisognerebbe comunque trovare).

Dal punto di vista del software di ricognizione, ho realizzato due moduli, dei quali risparmio il codice, a meno che non lo si ritenga utile, il primo (~100 righe + test] dedicato a rilevare le schede fisiche di rete ed i relativi IP4 oltre che alla scansione delle porte di ascolto, tramite socket, nell'intervallo 1-254 delle sotto-reti individuate nella macchina, il secondo (~250 righe + test) si occupa di stabilire i tentativi di connessione ed identificazione dei server "giusti" (nella rete ho identificato diversi "servizi" che non sono locali).

Or bene, sono consapevole che la modalità su esposta, pur se funzionale è senz'altro rozza, non mi sono mai interessate le problematiche di "rete" ed ho dovuto improvvisare in fretta, la domanda è :

Siete a conoscenza di modalità migliori per impostare ed individuare in lan locale dei server di cui non conoscete l'indirizzo? E se si, sapreste darmi indicazione di dove/come acquisire le tecniche necessarie?

Grazie dell'attenzione, i miei saluti.

5
Base / [Risolto] Aggiornamento output nel terminale con end=''
« il: Ottobre 05, 2019, 18:49 »
Signori, i miei saluti.

In fase di test di una classe in sviluppo per un oggetto dedicato alla scansione di lan locale per l'individuazione di eventuali hosts  in ascolto ho riscontrato un curioso "effetto" utilizzando una istruzione
print('.', end='')

con output destinato ad un normale trminale bash : l'output relativo NON viene mostrato prima della conclusione del processo (un po' lunghetto).

Il problema si presenta anche in caso si utilizzi uno spazio quale terminazione del print mentre funziona regolarmente in caso di utilizzo di un newline.

... Curioso ma non stranissimo il fenomeno, mi sta facendo "incarognare" ma per quanto ci giri attorno e cerchi in rete non sto trovando soluzione (un time.sleep(qualcosa) non serve), non riesco a far aggiornare quel dannato output.
È probabile la "soluzione" sia banale ma proprio non mi riesce di immaginare dove altro cercarla ... qualcuno conosce la problematica?

Non credo se serva in merito, ma giusto in caso io ne sia inconsapevole causa, questo è l'oggetto che dovrebbe produrre quell'output (con tutte le "sporcature" del litigio

class ScanPortLan():
    '''
Esegue la scansione di una specifica porta su tutti gli indirizzi della rete
locale al fine di individuare su quali macchine vi è "qualcosa" in ascolto.
    '''
    def __init__(self, ip, porta):
        '''
Inizializzazione dell'oggetto, memorizza quali variabili di istanza l'indirizzo
locale e la porta da verificare.

Parametri : ip    - stringa dell'indirizzo ipv4 della macchina
            porta - porta da verificare
        '''
        self.ind_ascolto = []
        self.my_ip = ip
        self.porta = porta
        self.scan()
   
    def scan(self):
        '''
Tenta una connessione alla porta definita nel range 1/254 della rete locale,
escluso il proprio indirizzo.
Memorizza gli indirizzi che hanno dato risposta.
        '''
        base = self.my_ip.split('.')
        base_ind = '.'.join(base[:-1])
        for p in range(1, 255):
            curr_ip = base_ind + '.' + str(p)
            if curr_ip != self.my_ip:
                if self.connetti(curr_ip):
                    print('\n', curr_ip, '<-->', 'CONNESSO')
                    self.ind_ascolto.append(curr_ip)
                else:
                #print('.', end='')
                    #print('.', end=' ')
                    print('.', end='\n')
                    #print('.')
            time.sleep(0.5)
        print()
        print('Hosts in ascolto:')
        for ip in self.ind_ascolto:
            print('\t', ip)
   
    def connetti(self, ip):
        try:
            s = socket.socket(socket.AF_INET)
            s.settimeout(0.5)
            s.connect((ip, self.porta))
            result = True
        except OSError:
            result = False
        finally:
            if s:
                s.close()
        return result

Manca la restituzione di quanto trovato.

questa è la sua corrente invocazione di test

if __name__ == '__main__':
    llhr = LocalLanHdwRec()
    for ip in llhr.get_ip4():
        ScanPortLan(ip, 21)


e questo è un esempio della disdicevole casistica :

NzP:~$ python3 recognizer.py
^C..............Traceback (most recent call last):
  File "recognizer.py", line 106, in <module>
    ScanPortLan(ip, 21)
  File "recognizer.py", line 64, in __init__
    self.scan()
  File "recognizer.py", line 82, in scan
    time.sleep(0.5)
KeyboardInterrupt
NzP:~$ python3 recognizer.py


Ciao e grazie dell'attenzione :)

6
I miei saluti.

Per una "trasformazione" della lan locale, da IP statici definiti localmente a DHCP non controllabile localmente, mi sto ponendo domande su come individuare alcuni server in lan locale (database, ftp, ssh etc.) in un ambiente ad IP variabili.

La soluzione più immediata che mi è venuta in mente è individuare gli indirizzi tcp-ip locali alla macchina e poi fare una scansione del range 1 - 254 della sotto-rete locale per vedere su quali indirizzi le porte dei server sono aperte ed in ascolto.

Individuare gli indirizzi IP locali alla macchina mi è riuscito utilizzando il modulo "netifaces", in questo modo :
>>> import netifaces as ni
>>> nif = ni.interfaces()
>>> for scheda in nif:
print('Interfaccia :', scheda)
diz_ind = ni.ifaddresses(scheda)
for chiave in diz_ind.keys():
if chiave == 2:
print('%3s' % chiave, diz_ind[chiave])
print()


Interfaccia : lo
  2 [{'addr': '127.0.0.1', 'netmask': '255.0.0.0', 'peer': '127.0.0.1'}]

Interfaccia : enp2s0
  2 [{'addr': '192.168.60.28', 'netmask': '255.255.255.0', 'broadcast': '192.168.60.255'}]

>>>


Ma vorrei limitare le scansioni alle sole schede "fisiche" presenti nel sistema, evitando interfacce di loobpack e virtuali, è un po' che cerco nella documentazione ma non mi riesce di individuare niente di utile in merito a come effettuare una tale distinzione, avreste delle indicazioni da darmi in proposito?

Grazie dell'attenzione :)

7
I miei saluti a Voi.

Cercando di realizzare un "controllo" personalizzato (assemblando vari widget) ho provato, tra l'altro, una "composizione" che prevede l'utilizzo di una scrollbar non associata alla view di un secondo widget.
L'utilizzo della scrollbar è relazionato al solo scorrimento di un indice di lista dati.

La prova, tutto sommato, ha avuto successo, almeno in linea di massima, in questo modo :
dichiarazione nello __init_della classe :
        self.pivot_scroll = tk.Scrollbar(self,
                                         orient=tk.VERTICAL,
                                         jump=1,
                                         command=self._scrollEvent)

l'opzione "jump=1" è data per limitare gli eventi al solo rilascio del tasto del mouse

definizione del "set" per la scrollbar al caricamento dei dati :
    def set_data(self, dati):
        self.dati = dati
        self.pivot = 0
        for riga in self.rows:
            riga.clear()
        # configurazione scrollbarr
        self.pivot_scroll.set(0, len(self.dati) - self.righe)
        # fine per scroll
        self._refresh_rows()

ove viene impostato, per la scrollbar, un "intervallo" pari alla consistenza dei dati decurtata degli elementi visualizzati, tale impostazione è necessaria, in assenza si hanno "out of range" ad ogni evento proveniente dalla scrollbar

gestito valutando i dati passati dalla scrollbar al gestore (handler, se volete) associato
    def _scrollEvent(self, *L):
        """Gestisce lo scroll della vertical barr associata."""
        if not self.dati: return
        for elem in L: print(elem, end=' - ')
        print()
        op, valore = L[0], L[1]
        if op == 'scroll':
            modo = L[2]
            if modo == 'pages':
                val = int(valore) * self.righe
            else:
                val = int(valore)
            if (self.pivot + val) < 0:
                self.pivot = 0
            elif (self.pivot + val) > (len(self.dati) - self.righe):
                self.pivot = len(self.dati) - self.righe
            else:
                self.pivot += val
        elif op == 'moveto':
            self.pivot += int(len(self.dati) * float(valore)) - 1
            if self.pivot < 0:
                self.pivot = 0
            elif self.pivot > len(self.dati) - self.righe:
                self.pivot = len(self.dati) - self.righe
        self._refresh_rows()


Come detto, le impostazioni sopra per funzionare funzionano ma in modo insoddisfacente : lo slider della scrollbar assume la dimensione dell'intera area disponibile, cosa non sorprendente, e (questo è strano) si "ridimensiona" in caso di trascinamento a partire dai bordi estremi dello stesso, tale ridimensionamento permate e da quel momento è possibile "agganciare" e trascinare lo slider, la "precisione" lascia a desiderare ed il posizionamento effettivo dello slider è insussistente.
Se occorressero maggiori dettagli od una visualizzazione grafica della circostanza potete vedere qui, sono semplici appunti di apprendimento.

Non so se è possibile farlo ma vorrei realizzare un controllo adeguato della rappresentazione dei dati visualizzati in rapporto all'insieme degli stessi, il tutto completamente avulso da view di elementi grafici.
Ho molto cercato e letto ma ho trovato pochissimo, se non nulla, di specifico in merito ad una definizione  delle specifiche dello slider o, magari, ci sono incappato e non ho compreso, data la mia ignoranza dell'inglese.

Qualcuno di Voi avrebbe indicazioni e/o suggerimenti in merito?

Grazie dell'attenzione  :caffè:

8
Base / Storage parametri applicazione : un consiglio
« il: Aprile 20, 2019, 12:43 »
Buon giorno a Voi ... e buona Pasqua, data la prossimità :)

Desidererei un consiglio :
nei sistemi unix-like è ampiamente usato memorizzare parametri opzionali di una applicazione scelti da un utente in una direttrice nascosta nella home dell'utente, cosa semplice da realizzare con python

import os
...
def load_app_configurations():
    '''Acquisisce, se esistono, le scelte applicative salvate.'''
    home = os.path.expanduser('~')
    app_dir = os.path.join(home, '.app_name')
    if not os.path.exists(app_dir):
        os.mkdir(app_dir)

mi apprestavo ad utilizzare una tale metodologia ma mi son fermato un attimo, so che "funzionerebbe" anche in windows, almeno per alcune versioni, ma mi chiedo se esiste una qualche convenzione/linea guida in merito, almeno per l'ambito python ...  sapreste darmi suggerimenti in merito?

9
Tkinter / [Risolto] layout "grid", classi e persistenza oggetti
« il: Aprile 15, 2019, 09:19 »
I miei saluti a Voi :)

Intrigato da una idea reperita altrove, mi sono avventurato a costruire una specie di "controllo" composito con tkinter che provvede ad esporre righe di immagini miniaturizzate e didascalie. Nel costruirlo mi sono anche scritto una serie di test per verificare la "resa" di quanto fatto in vali punti di sviluppo.

Ho implementato una versione utilizzante il metodo "pack()" costituita da due classi, una definente una singola "riga" dati (immagine/didascalia) mentre la seconda visualizza un insieme di tali righe e fornisce i metodi per la navigazione tra i dati. Tale versione è funzionante.

Insoddisfatto da alcune questioni di resa grafica degli automatismi di pack() ho provato a definire una variante dell'oggetto utilizzante il metodo "grid()" ed incappando già alla definizione della singola riga in una serie di problematiche che, dopo un po' di ricerche e prove, credo si individuino in una mancata persistenza degli oggetti invocati dal codice per una qualche peculiarità del metodo grid() che non mi riesce di individuare, probabilmente per la mia ignoranza dell'inglese (enorme palla al mio piede)

Appresso, esemplifico il codice, funzionante, del costruttore di una riga, versione utilizzante pack(), e della sua invocazione, con inseriti del print di debug.

costruttore :

class FRMTumbnail(tk.Frame):
    '''Pannello per singola miniatura (tumbnail) con descrizione.'''
    def __init__(self, master, mater, imgdim=60):
        self.mater = mater
        self.f_img = ''
        super().__init__(master)
        self.dim_tmb = imgdim
        self._curr_img = None
        self.indice = None
        self.default_bc = self.cget('bg')
        self.configure(relief='sunken', border=2, padx=2, pady=2)
        self.cnv_tmb = tk.Canvas(self,
                                 width=self.dim_tmb,
                                 height=self.dim_tmb,
                                 bg='#ffffc0',
                                 relief='raised',
                                 border=2
                              )
        self.cnv_tmb.pack(side='left')
        print('self.cnv_tmb è : ', self.cnv_tmb)
        print(self.cnv_tmb)
        self.cnv_tmb.bind('<Button-1>', self._scelto)
        f = tk.Frame(self, height=self.dim_tmb+4)
        f.pack(side='left', expand=True, fill='x')
        #f.pack_propagate(0)
        self.lbl_dida = tk.Label(f,
                                text='..'*10,
                                justify='left',
                                )
        self.lbl_dida.pack(expand=True, fill='both')
        print('self.lbl_dida è : ', self.lbl_dida)
        self.lbl_dida.bind('<Button-1>', self._scelto)


invocazione:

class GUI_01(tk.Tk):
    ''' Finestra principale test 01 : singola riga. '''

    def __init__(self, fnome='', dim=60):
        super().__init__()
        self.f_nome = fnome
        self.title('Test 01')
        sfondo = tk.Frame()
        sfondo.pack(fill='both')
        self.f = fd.FRMTumbnail(sfondo, None, dim)
        self.f.pack(fill='x')
        print('self.f è : ', self.f)
        f2 = tk.Frame(sfondo, relief='sunken', padx=2, pady=2)
        f2.pack(fill='x')
        btn = tk.Button(f2, text='Mostra immagine', command=self.mostra)
        btn.pack()
        self.minsize(300, self.winfo_reqheight())
        # self.update()
        centraFinestra(self)
   
    def mostra(self):
        self.f.set_fileimg(self.f_nome)
        self.f.set_dida("un po' di testo a caso")


Ed ora analoghi costruttore ed invocazione con grid(), si noti il commento dei "bind()", con ciò la riga viene visualizzata correttamente ma è inutilizzabile.

Costruttore:

class GriFRMTmb(tk.Frame):
    '''Pannello per singola miniatura (tumbnail) con descrizione.'''
    def __init__(self, master, mater, imgdim=60):
        self.mater = mater
        self.f_img = ''
        super().__init__(master)
        self.dim_tmb = imgdim
        self._curr_img = None
        self.indice = None
        self.default_bc = self.cget('bg')
        self.configure(relief='sunken', border=2, padx=2, pady=2)
        self.cnv_tmb = tk.Canvas(self,
                                 width=self.dim_tmb,
                                 height=self.dim_tmb,
                                 bg='#ffffc0',
                                 relief='raised',
                                 border=2
                                 ).grid(row=0, column=0, sticky='w')
        print('self.cnv_tmb è : ', self.cnv_tmb)
        #self.cnv_tmb.bind('<Button-1>', self._scelto)
        self.lbl_dida = tk.Label(self,
                                text='...',
                                justify='left',
                                ).grid(row=0, column=1, sticky='nsew')
        #self.lbl_dida.bind('<Button-1>', self._scelto)
        print('self.lbl_dida è : ', self.lbl_dida)
        self.columnconfigure(1, weight=1)


invocazione:

class GUI_01_G(tk.Tk):
    ''' Finestra principale test 01 - variante layout grid : singola riga. '''

    def __init__(self, fnome='', dim=60):
        super().__init__()
        self.f_nome = fnome
        self.title('Test 01-Grid')
        sfondo = tk.Frame().grid(sticky='nsew')
        self.f = fd.GriFRMTmb(sfondo, None, dim).grid(row=0,
                                                        padx=2,
                                                        pady=2,
                                                        sticky='ew'
                                                        )
        print('self.f è : ', self.f)
        btn = tk.Button(sfondo,
                        text='Mostra immagine',
                        command=self.mostra).grid(row=1,
                                                  padx=2,
                                                  pady=2,
                                                  sticky='nsew'
                                                  )
        self.columnconfigure(0, minsize=300, weight=1)
        self.update()
        centraFinestra(self)
   
    def mostra(self):
        self.f.set_fileimg(self.f_nome)
        self.f.set_dida("un po' di testo a caso")

(mi si perdoni l'incompleta aderenza alla Pep8)

e qui segue l'output del test effettuato per le due versioni :

NzP:~$ python3 test.py 1 risorse/01.jpg 60
self.cnv_tmb è :  .!frame.!frmtumbnail.!canvas
.!frame.!frmtumbnail.!canvas
self.lbl_dida è :  .!frame.!frmtumbnail.!frame.!label
self.f è :  .!frame.!frmtumbnail
NzP:~$ python3 test.py 5 risorse/01.jpg 60
self.cnv_tmb è :  None
self.lbl_dida è :  None
self.f è :  None
NzP:~$


Mi sembra evidente che con l'utilizzo di pack() le variabili di istanza nelle classi vengono correttamente create mentre utilizzando grid() invece no
 ... malgrado abbia cercato nella docs ed in rete mi son fermato qui, non mi riesce di capirne il perché e come rimediare, qualcuno di Voi conosce il problema e può darmi indicazioni in merito?

Scusate la lunghezza del post, non mi riuscirebbe di essere chiaro, altrimenti.

10
Salute a Voi.

Come da oggetto, per necessità lavorative mi serviva associare luogo, sesso e data di nascita a nominativi cui disponevo solo del codice fiscale, ho risolto "al volo" con un piccolo script dopo essermi scaricato il csv di codifica dei comuni italiani dal  sito dell'istat (se interessano tali dati l'indirizzo è : http://www.istat.it/storage/codici-unita-amministrative/Elenco-comuni-italiani.csv)

Un intoppo avuto al primo utilizzo del file è stato causato dalla conversione in utf-8 che falliva, risolto sbrigativamente immaginandolo di provenienza windows ed impostando una codifica 'ISO-8859-1' nell'apertura del file.

So benissimo che la codifica del testo proveniente da fonti sconosciute è una rogna "secolare" ma mi chiedo se tra le sterminate librerie di python ve ne è qualcuna in grado di dar soluzione al problema o, quanto meno, una convenzione in merito.
Da precedenti ricerche mi ero convinto che i files csv "dovessero" essere in codifica utf-8 ... ma pare che l'istat non concordi sulla cosa.

P.S. - tempo fa trovai chardet nelle librerie python, utile ma non troppo.

11
wxPython / wx.App.stdioWin ... ma dove si trova?
« il: Gennaio 04, 2019, 10:15 »
Salve, lo so che è una domanda da utonto, chiedo venia.

Sto seguendo l'ottima guida su wxPython di @RicPol (grazie @Ric, veramente ben fatta, complimenti) e son rimasto incuriosito dal commento in questa istruzione :
            app.stdioWin.close() # notare la "c" minuscola!


e sono andato a cercare di capire come mai quella "c" (ed anche la "s") non adotta l'onnipresente camelcase delle wx ... senza riuscire a trovar traccia di "stdioWin" tanto nelle api di "App" quanto in quelle di "AppConsole" (classe figlis di App cui riferiscono metodi come OnInit o OnEcit).

Mi è evidente che c'è qualcosa di contemporaneamente fondamentale e banale che non ho compreso, ritenevo stdioWin quale probabile metodo di classe che restituisce un oggetto "finestra" ma così non è e non ne sto venendo a capo ... potete illuminarmi?

[Edit] ... riguardando, l'ennesima volta, credo di aver (finalmente) capito che trattasi di una variabile (di classe o di istanza?), circostanza esplicitamente detta nel testo e che non avevo assimilato (sono condizionato dalle "scatole chiuse" java) e devo, quindi, andarmi a guardare la classe PyOnDemandOutputWindow per capire quella "c" :)

[ri-edit] ... e la spiegazione è semplicemente che ... per quella istruzione non è stato rispettato il CamelCase! come per flush() e write()  :D

12
Interfacce grafiche / Immagini e "contesti" grafici
« il: Ottobre 20, 2018, 11:13 »
Domanda forse un po' strana :

Che Voi sappiate esiste la possibilità di definire un oggetto immagine utilizzabile direttamente (senza specifiche istruzioni di caricamento) nei vari contesti grafici disponibili (pyTk, pyGtk, wxPyton, etc.)?

Un paio di giorni di ricerche in tal senso non hanno avuto esito e niente del poco che conosco è in tal senso ma data la notevole quantità di gestori presenti in python ed il grande numero di librerie esistenti (per lo più a me ignote) mi hanno spinto a porre la domanda.

Grazie dell'attenzione :)

13
Python-it.org cafè / Delle domande prima di cominciare
« il: Ottobre 09, 2018, 18:55 »
Salve ragazzi

come mio primo post in questo forum, devo dire molto serio e preciso, a quel che vedo, qualche domandina preliminare per non toppare troppo quando poi passerò a fare qualche post "tecnico", mi permetto di farla al "bar", mi sembra giusto così

1a
Guardando in giro, vedo in genere piccoli stralci di codice e trattare argomenti strettamente specifici, non che non mi interessino, anzi, ma essendo un "solitario autodidatta" ho sviluppato, nel tempo, mie abitudini implementative che mi ostacolano non poco con questo linguaggio e che vorrei mettere in discussione.
Lo so bene che è estremamente seccante, principalmente per gli esperti, ma : è ammesso esporre nei post del codice consistente?, che so tre-quattro moduli x un migliaio di righe

Da ciò discende la seconda domanda :
Non ricordo di aver visto, in questo forum, dei settori di testo scorrevole ... è possibile l'inserimento diretto di codice html in un post?
Ovviamente, l'idea è di un div, ad altezza fissa e larghezza in percentuale, non ho visto attrezzi analoghi

Se le domande sono banali scusate :)

14
Benvenuto e regolamento / Presentazione e saluti
« il: Ottobre 07, 2018, 11:37 »
Un saluto a Voi

È un po' che seguo ed approfitto di questo Forum, mi sembra doveroso, quindi, cercare di farvi parte.

Di me : vecchietto con cultura inadeguata (mai studiato inglese, in particolare) che cerca di tenere sveglie le meningi studiacchiando programmazione nel poco tempo disponibile, qualche esperienza in altri linguaggi, sto cercando di apprendere python, giusto per vederne le potenzialità, al momento.

Ovviamente, sono qui per apprendere da Voi, forse (ma è dubbio) per dare una mano a qualcuno se mi riesce.

Ciao ;)

Pagine: [1]