Jan 032008
 

Questo è un nuovo software che sto scrivendo come parco giochi per migliorarmi in python e qt4. Il nome cambierà (ho scoperto esserci un altro qtodo in circolazione). La versione 0.1 è quasi pronta, al momento la si trova solo sul repository git , repo.or.cz , dove l’ho registrato, mentre è possibile segnalare un bug su bts.grys.it se a qualcuno saltasse in mente di provarlo.

Dec 172007
 

Chi lavora con i toolkit grafici sa cosa sono dialog modali e non modali. In breve:

  • Un dialogo modale non consente di interagire con l’applicazione che l’ha aperto
  • Un dialog non modale lo consente

Per poter avere più dialoghi non modali, sembra che con le Qt (e PyQt4) si debba usare il seguente codice:
dlg = QtGui.QDialog()
dlggui = Ui_dialog()
dlggui.setupUi(dlg)
dlg.show()
dlg.exec_()

 Posted by at 2:13 pm  Tagged with:
Dec 042007
 

Ultimamente mi è venuto lo schizzo di mettermi a giocare con Git, il Version Control System usato tra l’altro per gestire i sorgenti Linux. Devo dire che dopo le prime incomprensioni (dovute principalmente a Windows a dire la verità ) sembra non essere male. Forse è anche troppo per le dimensioni del progettino con cui lo sto testando, ma così per provare può anche andare bene.Una cosa da ricordare: quando si fa una commit da Windows, i file devono essere in formato Unix, altrimenti git non gradisce molto l’iniziativa. (update: a questo di può ovviare usando lo switch –no-verify) Per la cronaca, il progettino è il software che farò vedere durante la serata introduttiva su python e qt che terrò al Lifos

Nov 232007
 

Anche se in questo caso dovrebbe essere “troppo tempo libero e una bash sono pericolosi”, nel pomeriggio ho deciso che in onore della mente dietro One Liners dovevo creare il “Tiradadi dei Man” ™E così dopo un po’ di sano smanettamento è nato questo comando:

echo `find /usr/share/man/ | awk '{FS=";"}{ print $NF}'` | awk '{FS=" "}{srand();print$ (int(10000*rand()) % NF)}' | awk -F "." '{print $1}' | xargs man

che fa appunto questo: estrae una pagina man a caso tra quelle installate. Funziona solo con bash. Ovviamente l’ho gia’ inserito su One Liners
Update: Elena mi ha fatto notare che in realtà “tiradadi dei man” dovrebbe essere “tiradadi dei Manowar”. La coincidenza è davvero divertente

Nov 202007
 

Se mentre programmi con Python (ma credo valda anche per altri linguaggi) utilizzando OpenGL ottieni questo errore, una della cause può essere che chiami la funzione glBegin() un numero di volte maggiore della funzione glEnd() Questo simpatico errore (avevo messo la glBegin() in un ciclo e la glEnd() fuori) mi ha tenuto bloccato per due giorni…

Nov 192007
 

Dopo un periodo di assestamento dovuto al viaggio di andata e ritorno verso QGraphicView, OpenBoat sta andando avanti. A questo punto, dopo aver accantonato l’idea di avere due stack di codice diversi per le viste 2D e 3D, dopo aver (follemente) pensato di avere un oggetto diverso per ogni vista, sono arrivato ad un risultato quasi decente: allo stato attuale OpenBoat disegna mezzo scafo ed il codice che serve a disegnare lo scafo completo sta arrivando.Questo punto è importante per vari motivi, non ultimo il fatto che è un passo cruciale nello sviluppo. Da qui infatti, una volta finito di implementare il motore di disegno, posso partire per implementare tutte le funzionalità legate al disegno e alla sua modifica. La scaletta dei lavori che attualmente penso di seguire è la seguente:

  1. finire il disegno della matrice di punti del mezzo scafo
  2. implementare il disegno dello scafo completo (abbastanza banale a dire la verità)
  3. implementare la modifica delle opzioni del programma
  4. completare il disegno dello scafo con le spline per avere il profilo corretto

Forse non sarà questo l’ordine, altre cose importanti da fare sono la gestione delle viste, il poter selezionare un oggetto, l’implementazione delle Subdivide Surface, non so a priori cosa mi servirà per andare avanti. Ad ogni modo, quello che era iniziato quasi per scommessa e su cui nessuno ci credeva (io per primo a dire la verità ) sta lentamente andando avanti e forse vedrà la luce.

Nov 142007
 

Dopo un po’ di codice scritto per usare il QGraphicView delle qt, sono tornato al QGLWidget. Il motivo è semplice: il primo, per quanto molto comodo da utilizzare è solo bidimensionale. Questo porterebbe ad avere due stack di codice per fare le cose. Dato che il 3D serve, sono tornato a OpenGL.Il ritorno a OpenGL comporta più codice da scrivere per la gestione della selezione degli oggetti e cose simili, ma mi evita la scrittura del codice per la visualizzazione in 3D del modello, cosa che evito volentieri, visto che di casini ne ho già parecchi così. Al momento, dopo essere tornato indietro a OpenGL, ho iniziato delle leggere modifiche alla GUI (soprattutto delle finestre figlie) e sono riuscito a tornare a dove ero arrivato con il QGraphicView, quindi disegno i punti dello scafo in 3 viste su 4, anzi, ora ho pure lo zoom che funziona :-)

Nov 092007
 

Finalmente OpenBoat disegna i primi punti dello scafo. Per il momento sono appunto solo punti, ma almeno si inizia la parte interessante dopo tutta una serie di lavori abbastanza noiosi. A questo punto, disegnare le linee corrette dovrebbe essere abbastanza facile e poi si comincia con la parte 3D vera e propria.Se il widget che sto usando (QGraphicsView) non mi farà qualche brutta sorpresa, come avevo pensato/sperato probabilmente entro fine anno OpenBoat riuscirà almeno a disegnare le linee di default dello scafo, con relative modifiche e salvataggi alle linee dello stesso. Se va spettacolarmente bene invece, entro fine anno potrei essere anche un po’ più avanti.Di sicuro è una bella iniezione di fiducia sulla possibilità di arrivare in fondo a questo progetto.

Oct 232007
 

Con la versione 4 delle Qt, non è più possibile avere le toolbar flottanti. Per ovviare al problema si può usare un altro widget, il QDockWidget, che fa proprio questo. Inoltre consente di inserire anche dei widget custom direttamente da Qt-Designer, cosa che non è possibile con le Toolbar. C’è però un problema: le toolbar, quando venivano spostate (es, dall’alto a sinistra) si ridimensionavano da sole e rimettevano a posto il layout. Il QDockWidget no. Però a tutto si può ovviare, quindi con un po’ di codice si supera anche questo problema. Prima di tutto bisogna creare nel QDockWidget un layout di tipo grid in cui vengono posizionati i controlli.Per un baco nel Pyuic 4, si deve aggiungere il QDockWidget alla mainwindow dell’applicazione manualmente, con questa riga di codice

window.addDockWidget(QtCore.Qt.RightDockWidgetArea, ui.dockWidget)

Una volta che tutto è pronto si può cominciare a risolvere il problema del layout.Per prima cosa bisogna connette il QDockWidget al segnale TopLevelChanged, in questo modo:

QtCore.QObject.connect(ui.dockWidget,QtCore.SIGNAL(“topLevelChanged(bool)”),ui.select)

Questo fa in modo che quando cambiate posizione al QDockWidget, venga chiamata il metodo select (o come decidete di chiamarla, magari qualcosa del tipo relayout). Il metodo in questione semplicemente ridispone i controlli a seconda del fatto che il QDockWidget sia da impaginare in verticale (quindi è “dockato” sul lato destro o sinistro) o in orizzontale (quindi sia “dockato” in alto o in basso).Il codice è banale:

def select(self):
ui.gridlayout.removeWidget(ui.comboBox)
ui.gridlayout.removeWidget(ui.toolButton)
ui.gridlayout.removeWidget(ui.toolButton_2)
ui.gridlayout.removeWidget(ui.toolButton_3)

area = window.dockWidgetArea(ui.dockWidget)

if area == QtCore.Qt.BottomDockWidgetArea or area == QtCore.Qt.TopDockWidgetArea:
ui.gridlayout.addWidget(ui.comboBox, 0, 0)
ui.gridlayout.addWidget(ui.toolButton, 0, 1)
ui.gridlayout.addWidget(ui.toolButton_2, 0, 2)
ui.gridlayout.addWidget(ui.toolButton_3, 0, 3)
if area == QtCore.Qt.LeftDockWidgetArea or area == QtCore.Qt.RightDockWidgetArea:
ui.gridlayout.addWidget(ui.comboBox, 0, 0)
ui.gridlayout.addWidget(ui.toolButton, 1, 0)
ui.gridlayout.addWidget(ui.toolButton_2, 2, 0)
ui.gridlayout.addWidget(ui.toolButton_3, 3, 0)

Semplicemente in caso di cambio tra verticale/orizzontare, tutti i controlli vengono riarrangiati (in questo caso) su una riga o su una colonna. In caso di più colonne e/o righe il codice non diventa più complicato, a meno che non si decida di fare qualcosa di dinamico.Rimangono fuori alcuni aspetti tipo ridimensionare correttamente il QDockWidget una volta ridisposti i controlli o eliminare le righe/colonne non utilizzate, ma la logica è questa.Un possibile miglioramento sarebbe quello di usare un layout verticale o orizzontale al posto della griglia

 Posted by at 12:20 pm  Tagged with:
Oct 232007
 

Se si vuole fare in modo che una grid (QTableWidget o simili) sia attiva ma non editabile o editabile solo in seguito a certi eventi, basta impostare la proprietà editTriggers al valore appropriato.I valori elencati sono i valori che possono essere selezionati, anche in combinazione tra di loro:

QAbstractItemView::NoEditTriggers Nessun edit
QAbstractItemView::CurrentChanged L’editing inizia quando l’item corrente è¨ cambiato
QAbstractItemView::DoubleClicked L’editing inizia quando si esegue un doppio click sull’item selezionato
QAbstractItemView::SelectedClicked L’editing inizia quando si esegue un singolo click sull’item selezionato
QAbstractItemView::EditKeyPressed L’editing inizia quando il tasto di editing predefinito èpremuto sull’item corrente
QAbstractItemView::AnyKeyPressed L’editing inizia quando viene premuto un tasto sull’item corrente
QAbstractItemView::AllEditTriggers L’editing inizia per tutti i valori sopra riportati
 Posted by at 12:12 pm  Tagged with:
Oct 232007
 

Come ogni programma che si rispetti, anche quelli scritti in PyQt4 hanno la possibilità di essere localizzati.Per poter fare la traduzione delle varie stringhe bisogna seguire vari passi:

1 – Preparare il file delle traduzioni

Il file delle traduzioni è un file che contiene le stringhe in una lingua base (esempio inglese) e le corrispondenti traduzioni nella lingua in cui si vuole localizzare il programma.La struttura del file è la seguente:<!DOCTYPE TS><TS><context> <name>D_MainWin</name> <message> <source>Skipper</source> <translation>Skipper</translation> </message> </context></TS>dove name indica la sezione di cui si parla (ne parliamo dopo), source indica la stringa di default e translation indica la stringa tradotta. Il resto è del formato del file.Una precisazione name indica il nome dell’oggetto che vogliamo localizzare, semplicemente il valore della proprieta objectName Una volta preparato il file (che deve avere estensione .ts) si lancia il programma Qt Linguist e dal menù file si seleziona la voce Release, questo creerà un file .qm cheè il file compilato, il modello ricorda il giro file.po/file.gmo di gettext in effetti. QT Linguist ha un buon help in linea, fate riferimento a questo per tutti i problemi.

2 – Usare i file delle traduzioniUna volta creato il file .qm, il più è¨ fatto. La localizzazione dei programmi è gestita dalla classe QTranslator. Il codice necessario per inizializzare il tutto sono queste 3 righe:translator =QtCore.QTranslator()translator.load(QtCore.QString(‘i18n_it’))QtGui.qApp.installTranslator(translator)Dove il file (i18n_it in questo caso) puòessere completo di un path (relativo o assoluto)

3 – Preparare il codiceUna volta preparato il necessario e istanziata la classe, per avere la traduzione effettiva basta usare la funzione tr(“ciao”) per ogni stringa che si vuole tradurre.La funzione tr si preoccupa di recuperare la stringa tradotta in base al file della lingua caricato.Ci possono essere due risultati:

  1. la funzione trova la traduzione : viene usata
  2. la funzione non trova la traduzione: non succede nulla e viene usata la stringa passata come argomento

Piccola nota: se usate QtDesigner per creare l’interfaccia, il programma inserirà da solo tutte le chiamate alla funzione tr all’atto della generazione dei file necessari. A questo punto basta aggiungerli al file .ts e rilasciarlo.

 Posted by at 12:01 pm  Tagged with:
Oct 232007
 

Contrariamente alla versione precedente, con la versione 4 di Qt-Designer, non è possibile assegnare ad un evento uno slot custom, cosa che era molto comoda. Per ovviare a questo problema bisogna collegare un evento ad uno slot custom manualmente, dopo la creazione dell’interfaccia. Ecco un esempio.

class MainWin(Ui_DMainWin):

def __init__(self):

pass

def CustomSignal(self):

print “Hello”

app = QtGui.QApplication(sys.argv)

window = QtGui.QDialog()

ui = MainWin()

ui.setupUi(window)

#Custom Signal connections

QtCore.QObject.connect(ui.Button, QtCore.SIGNAL(“clicked()”), ui.CustomSignal)

 Posted by at 11:55 am  Tagged with:
Oct 232007
 

La libreria Qt fornisce i dialoghi standard per la gestione di funzioni tipo Save, Open, Save As… e via dicendo. Però utilizzare i QFileDialog può essere un po’ ostico, soprattutto all’inizio. Ecco quindi un paio di cose da sapere. Filtri sui formati E’ possibile impostare una serie di filtri per i formati di file che sono gestiti, solo che non è proprio intuitivo o documentato chiaramente, almeno in PyQt4. I filtri per i formati file sono il 4 parametro (filter) dei metodi statici della classe QFileDialog e si deve specificare così: “html (*.html);;pdf (*.pdf);;All Supported Files (*.pdf *.html)” Formato selezionatoCome è possibile impostare l’elenco dei filtri, è anche possibile recuperare il tipo di file (filtro) selezionato dall’utente. Ovviamente anche qui, la cosa in PyQt è documentata male. Il sistema più comodo è questo:

fileType = QtCore.QString("html *.html")
nfileName = QtGui.QFileDialog.getSaveFileName(None,
        "SaveAs...",
	".",
	"html (*.html);;pdf (*.pdf);; All Supported Files (*.pdf *.html)",
        fileType)

Dopo la chiusura del dialogo, fileType conterrà il filtro selezionato nella forma html (*.html)Attenzione al tipo del parametro fileType: deve essere di tipo QString, o la cosa non funziona.Il dialogo inoltre ritorna il nome del file con il percorso completo.

 Posted by at 11:30 am  Tagged with:
Jul 072005
 

Bella la prima notizia con cui iniziare questa specie di blog:

<b>con 648 voti su 680 la direttiva europea sui brevetti è stata definitivamente affossata</b>

ed era ora.

Così almeno in Europa si potrà tranquillamente continuare a sviluppare Software Open Source.