PyQt: Tutorial per iniziare

qttutorial

Ritorna alla pagina <-- Modifica precedente | Modifica successiva -->

Sommario diffierenze
Titolo PyQt: Tutorial per iniziare (WORK IN PROGRESS) PyQt: Tutorial per iniziare (WORK IN PROGRESS)
Data 2009-10-10 17:39:41 2009-10-10 17:57:26
Autore shainer shainer
Tags

2009-10-10 17:39:41 di shainer
2009-10-10 17:57:26 di shainer
nn1.. contents::
2
1Introduzione3Introduzione
2#######################4#######################
35
4PyQt4 è il porting delle librerie grafiche Qt per 6PyQt4 è il porting delle librerie grafiche Qt per 
>il linguaggio Python.>il linguaggio Python.
5PyQt4 è basato su moltissime classi e moduli. Alcu7PyQt4 è basato su moltissime classi e moduli. Alcu
>ni esempi di moduli sono:>ni esempi di moduli sono:
296*setSpacing*: le due precedenti, combinate.298*setSpacing*: le due precedenti, combinate.
297*setColumnMinimumWidth*: larghezza minima della co299*setColumnMinimumWidth*: larghezza minima della co
>lonna specificata come primo parametro.>lonna specificata come primo parametro.
298*setRowMinimumWidth*: stessa cosa per una riga.300*setRowMinimumWidth*: stessa cosa per una riga.
299*int columnCount*: ritorna il numero di colonne de301*int columnCount*: ritorna il numero di colonne de
>lla griglia.>lla griglia.
300*int rowCount*: ritorna il numero di righe.302*int rowCount*: ritorna il numero di righe.
tt303
304Menu
305#####
306
307Andiamo a definire un semplice menu.::
308
309  #!/usr/bin/python
310
311  import sys
312  from PyQt4 import QtGui, QtCore
313
314  class MainWindow(QtGui.QMainWindow):
315
316        def mySlot(self):
317                print "Menu voice has been hovered
 >"
318        
319        def __init__(self):
320                QtGui.QMainWindow.__init__(self)
321                self.setWindowTitle('Menu')
322
323                quit = QtGui.QAction(QtGui.QIcon("
 >icons/cancel.png"), "Quit", self)
324                quit.setShortcut("Ctrl+Q")
325                quit.setStatusTip("Quit applicatio
 >n")
326                self.connect(quit, QtCore.SIGNAL('
 >triggered()'), QtCore.SLOT('close()'))
327                
328                sep = QtGui.QAction(self)
329                sep.setSeparator(True)
330
331                info = QtGui.QAction(QtGui.QIcon("
 >icons/information.png"), "Information", self)
332                info.setShortcut("Ctrl+I")
333                info.setStatusTip("Show informatio
 >n")
334                self.connect(info, QtCore.SIGNAL('
 >hovered()'), self.mySlot)
335        
336                self.statusBar().show()
337                
338                menuB = self.menuBar()
339                file = menuB.addMenu('&File')
340                file.addAction(quit)
341                file.addAction(sep)
342                file.addAction(info)
343
344  app = QtGui.QApplication(sys.argv)
345  main = MainWindow()
346  main.show()
347  sys.exit(app.exec_())
348
349.. img:: 12
350   :nolink:
351
352In ordine di “importanza”, i passi sono:
353
354* creare una menuBar (la nostra menuB)
355* aggiungere tutti i menu che vogliamo creare con 
 >il metodo *addMenu()*. Questo metodo prende come a
 >rgomento una stringa. Il carattere preceduto dal s
 >imbolo & funge da scorciatoia: premendo Alt+caratt
 >ere attiveremo il menu corrispondente.
356* Ad ogni menu vanno poi aggiunge le singole *QAct
 >ion*, ovvero le voci di menu.::
357
358                quit = QtGui.QAction(QtGui.QIcon("
 >icons/cancel.png"), "Quit", self)
359                quit.setShortcut("Ctrl+Q")
360                quit.setStatusTip("Quit applicatio
 >n")
361                self.connect(quit, QtCore.SIGNAL('
 >triggered()'), QtCore.SLOT('close()'))
362
363Il costruttore di *QAction* permette di specificar
 >e subito il path dell'icona e il testo della voce 
 >di menu, oppure di ometterlo e di indicarlo dopo c
 >on i metodi appositi:::
364
365                quit = QtGui.QAction(self)
366                quit.setText(“Quit”)
367                quit.setIcon(QtGui.QIcon(“icons/qu
 >it.png”)
368
369Questi ultimi due codici danno lo stesso identico 
 >risultato.
370Il metodo *setText()* merita particolare attenzion
 >e: infatti esso si può trovare in diversi widget c
 >he comprendono un testo (pulsanti, etichette, etc.
 >..) per modificare il testo che accompagna il widg
 >et stesso. Il corrispondente che invece ritorna il
 > testo corrente sotto forma di *QString* è semplic
 >emente *text()*.
371Eccezione: per le *textEdit*, che possono contener
 >e non solo testo semplice ma anche HTML, invece di
 > *text()* si ha *toPlainText()*.
372Per ritornare la shortcut o lo statustip correnti 
 >potete usare i metodi *statusTip()* e *shortcut()*
 >.
373Il secondo oggetto non rappresenta una voce di men
 >u, ma semplicemente un separatore: per questo nel 
 >costruttore non passiamo nessun argomento.
374
375Nel codice precedente sono mostrati due segnali ti
 >pici dei menu: *triggered()* viene emesso quando l
 >'utente clicca su una voce di menu. ATTENZIONE: no
 >n viene dunque emesso il segnale *clicked()* come 
 >si potrebbe pensare! Invece *hovered()* è emesso q
 >uando il mouse passa sulla voce di menu.
376Ultima nota: per le voci di menu è presente anche 
 >il metodo *setCheckable()* (e *setChecked()*, per 
 >specificare l'azione iniziale), identico a quello 
 >usato per i toggle button in precedenza: se viene 
 >passato il parametro True, l'icona della voce si c
 >omporterà proprio come un toggle button.
377
378Toolbar
379########
380
381Una toolbar è un insieme di pulsanti che assolvono
 > ad alcune funzioni di base. In alcuni casi può es
 >sere più comoda di un menu perché permette all'ute
 >nte di scegliere l'azione più velocemente.::
382
383  #!/usr/bin/python
384
385  import sys
386  from PyQt4 import QtGui, QtCore
387
388class MainWindow(QtGui.QMainWindow):
389        
390        def __init__(self):
391                QtGui.QMainWindow.__init__(self)
392
393                self.setWindowTitle('Toolbar')
394
395                quit = QtGui.QAction(QtGui.QIcon("
 >icons/cancel.png"), "Quit", self)
396                quit.setShortcut("Ctrl+Q")
397                quit.setStatusTip("Quit applicatio
 >n")
398                self.connect(quit, QtCore.SIGNAL('
 >triggered()'), QtCore.SLOT('close()'))
399                
400                sep = QtGui.QAction(self)
401                sep.setSeparator(True)
402
403                info = QtGui.QAction(QtGui.QIcon("
 >icons/information.png"), "Info", self)
404                info.setShortcut("Ctrl+I")
405                info.setStatusTip("Show informatio
 >n")
406        
407                self.statusBar().show()
408                
409                toolbar = self.addToolBar('My tool
 >')
410                toolbar.addAction(quit)
411                toolbar.addAction(info)
412                toolbar.setToolButtonStyle(QtCore.
 >Qt.ToolButtonTextUnderIcon)
413
414  app = QtGui.QApplication(sys.argv)
415  main = MainWindow()
416  main.show()
417  sys.exit(app.exec_())
418
419.. img:: 15
420   :nolink:
421
422Come è possibile notare, il codice non è troppo di
 >verso da quello usato per i menu. Le varie “action
 >” si dichiarano sempre allo stesso modo, ma alla f
 >ine invece di dichiarare barre e menu, ci limitiam
 >o ad una toolbar.
423Il metodo *setToolButtonStyle()* permette di speci
 >ficare la presenza del testo e nel caso, la sua po
 >sizione. Gli argomenti che possiamo passargli (olt
 >re a quello indicato, che posiziona il testo sotto
 > l'icona) sono: *Qt.ToolButtonTextBesideIcon* (tes
 >to accanto all'icona), *Qt.ToolButtonTextOnly* (so
 >lo testo), *Qt.ToolButtonIconOnly* (solo l'icona, 
 >l'azione predefinita).
424Altro metodo è *setOrientation()*: accetta come ar
 >gomenti *Qt.Horizontal* o *Qt.Vertical*.
425
426Dialogs
427########
428
429Le dialog window sono “popup”, piccole finestrelle
 > che possono essere dipendenti o meno da quella pr
 >incipale. Vengono utilizzate per visualizzare brev
 >i messaggi o per prendere input.
430PyQt4 mette a disposizione diversi dialogs standar
 >d per le operazioni più comuni: vediamo in un unic
 >o codice come si dichiarano, e come vengono ritorn
 >ate le informazioni.::
431
432  #!/usr/bin/python
433
434  import sys
435  from PyQt4 import QtGui, QtCore
436
437  class MainWindow(QtGui.QMainWindow):
438        def __init__(self):
439                QtGui.QMainWindow.__init__(self)
440                buttons = [0] * 13
441                self.titles = ["Get integer", "Get
 > double", "Get item", "Get text", "Set color", "Se
 >t font", "Set directory", "Open file", "Save File"
 >, "Critical message", "Info message", "Question", 
 >"Warning"]
442                slots = [self.getInt, self.getDoub
 >le, self.getItem, self.getText, self.getColor, sel
 >f.getFont, self.getDirectory, self.openFile, self.
 >saveFile, self.Critical, self.Info, self.Question,
 > self.Warning]
443                
444                self.resize(350, 250)
445                self.setWindowTitle('Dialogs')
446                
447                widget = QtGui.QWidget(self)
448                
449                grid = QtGui.QGridLayout(widget)
450                grid.setVerticalSpacing(10)
451                grid.setHorizontalSpacing(8)
452
453                row = 0
454                col = 0
455                
456                for i in range(13):
457                        buttons[i] = QtGui.QPushBu
 >tton(self.titles[i], widget)
458                        self.connect(buttons[i], Q
 >tCore.SIGNAL('clicked()'), slots[i])
459                        
460                        grid.addWidget(buttons[i],
 > row, col)
461                        
462                        if col == 2:
463                                col = 0
464                                row += 1
465                        else:
466                                col += 1
467                
468                self.textEdit = QtGui.QTextEdit(wi
 >dget)
469                self.textEdit.setReadOnly(True)
470                grid.addWidget(self.textEdit, 5, 0
 >, 1, 3)
471                
472                self.setLayout(grid)
473                self.setCentralWidget(widget)
474                
475        def getInt(self):
476                integer, ok = QtGui.QInputDialog.g
 >etInteger(self, self.titles[0], "Integer: ", 9, 0,
 > 1000, 1)
477                
478                if ok:
479                        self.textEdit.append(self.
 >tr("%1").arg(integer))
480
481        def getDouble(self):
482                double, ok = QtGui.QInputDialog.ge
 >tDouble(self, self.titles[1], self.tr("Amount:"), 
 >37.56, -10000, 10000, 1)
483        
484                if ok:
485                        self.textEdit.append(self.
 >tr("%1").arg(double))
486                        
487        def getItem(self):
488                items = QtCore.QStringList()
489                items << "GNU/Linux" << "Windows" 
 ><< "Macintosh" << "QNX"
490                
491                item, ok = QtGui.QInputDialog.getI
 >tem(self, self.titles[2], "OS", items, 0, False)
492                
493                if ok and item.isEmpty() == False:
 >
494                        self.textEdit.append(item)
 >
495        
496        def getText(self):
497                text, ok = QtGui.QInputDialog.getT
 >ext(self, self.titles[3], "Enter your name:")
498                
499                if ok and text.isEmpty() == False:
 >
500                        self.textEdit.append(text)
 >
501        
502        def getColor(self):
503                color = QtGui.QColorDialog.getColo
 >r(QtCore.Qt.blue, self)
504                
505                if color.isValid():
506                        self.textEdit.setTextColor
 >(color)
507                        self.textEdit.append(color
 >.name())
508        
509        def getFont(self):
510                font, ok = QtGui.QFontDialog.getFo
 >nt()
511                
512                if ok:
513                        self.textEdit.setFont(font
 >)
514                        self.textEdit.append(font.
 >key())
515        
516        def getDirectory(self):
517                directory = QtGui.QFileDialog.getE
 >xistingDirectory(self, self.titles[6], "Select dir
 >ectory:", QtGui.QFileDialog.ShowDirsOnly)
518                
519                if directory.isEmpty() == False:
520                        self.textEdit.append(direc
 >tory)
521        
522        def openFile(self):
523                fName = QtGui.QFileDialog.getOpenF
 >ileName(self, self.titles[7], "Open new file", sel
 >f.tr("All Files (*);;Text Files (*txt)"))
524                
525                if fName.isEmpty() == False:
526                        self.textEdit.append(fName
 >)
527        
528        def saveFile(self):
529                fName = QtGui.QFileDialog.getSaveF
 >ileName(self, self.titles[8], "Save a new file", s
 >elf.tr("All Files(*)"))
530
531                if fName.isEmpty() == False:
532                        self.textEdit.append(fName
 >)     
533                        
534        def Critical(self):
535                reply = QtGui.QMessageBox.critical
 >(self, self.titles[9], "Critical message!", QtGui.
 >QMessageBox.Abort, QtGui.QMessageBox.Ignore, QtGui
 >.QMessageBox.Retry)
536                
537                if reply == QtGui.QMessageBox.Abor
 >t:
538                        self.textEdit.append("Abor
 >t")
539                elif reply == QtGui.QMessageBox.Re
 >try:
540                        self.textEdit.append("Retr
 >y")
541                else:
542                        self.textEdit.append("Igno
 >re")
543        
544        def Info(self):
545                QtGui.QMessageBox.information(self
 >, self.titles[10], "Information message")
546        
547        def Question(self):
548                reply = QtGui.QMessageBox.question
 >(self, self.titles[11], "Are you sure?", QtGui.QMe
 >ssageBox.Yes, QtGui.QMessageBox.No)
549                
550                if reply == QtGui.QMessageBox.Yes:
 >
551                        self.textEdit.append("Yes"
 >)
552                else:
553                        self.textEdit.append("No")
 >
554        
555        def Warning(self):
556                reply = QtGui.QMessageBox.warning(
 >self, self.titles[12], "Warning!", "Try again", "C
 >ontinue")
557                
558                if reply == 0:
559                        self.textEdit.append("Try 
 >again")
560                else:
561                        self.textEdit.append("Cont
 >inue")
562        
563  app = QtGui.QApplication(sys.argv)
564  main = MainWindow()
565  main.show()
566  sys.exit(app.exec_())
567
568Per guadagnare in chiarezza, abbiamo posto i pulsa
 >nti, i testi degli stessi e gli slots in degli arr
 >ay. Il codice all'interno del ciclo for si occupa 
 >di inizializzarli e sistemarli all'interno della g
 >riglia.::
569
570                integer, ok = QtGui.QInputDialog.g
 >etInteger(self, self.titles[0], "Integer: ", 9, 0,
 > 1000, 1)
571
572Il metodo *getInteger()* richiede i seguenti param
 >etri: *self*, una stringa da usare come titolo, un
 >'altra da inserire all'interno del dialog, e quatt
 >ro valori numerici. Il primo indica il valore di d
 >efault, il secondo il valore minimo selezionabile,
 > il terzo il valore massimo, e infine l'ultimo val
 >ore indica di quanti numeri si deve andare avanti/
 >indietro quando si premono le freccette a lato. Ad
 > esempio se mettete 2, e poi cliccate sulla frecce
 >tta in alto, si passerà da 9 direttamente ad 11.::
 >
573
574                double, ok = QtGui.QInputDialog.ge
 >tDouble(self, self.titles[1], self.tr("Amount:"), 
 >37.56, -10000, 10000, 1)
575
576Cosa simile vale per l'input di valori double, ovv
 >ero con virgola mobile.::
577
578                items << "GNU/Linux" << "Windows" 
 ><< "Macintosh" << "QNX"
579                
580                item, ok = QtGui.QInputDialog.getI
 >tem(self, self.titles[2], "OS", items, 0, False)
581
582In questo dialog, ci viene proposta una scelta fra
 > degli elementi predefiniti. La variabile *items* 
 >li contiene. Gli ultimi due parametri di *getItem(
 >)* indicano rispettivamente l'indice della stringa
 > da visualizzare di default e un'indicazione rispe
 >tto al layout. Provare a sostituire False con True
 > per vedere la differenza.::
583
584        def getColor(self):
585                color = QtGui.QColorDialog.getColo
 >r(QtCore.Qt.blue, self)
586
587Qui l'unico parametro interessante è il primo: il 
 >colore di default. È un parametro opzionale, e se 
 >viene omesso è settato a *QtCore.Qt.white*.
588
589Altri widgets
590##############
591
592textEdit
593=========
594
595Anche se abbiamo già incontrato questo widget in p
 >recedenza, in realtà esistono altri metodi di cui 
 >non abbiamo parlato. Il prossimo codice ne usa una
 > buona parte per creare un rudimentale editor, di 
 >nome Tiny Editor.::
596
597  #!/usr/bin/python
598
599  import sys
600  from PyQt4 import QtGui, QtCore
601
602  class MainWindow(QtGui.QMainWindow):
603        def createMenuVoice(self, iconPath, name, 
 >shortcut, tip, slot):
604                voice = QtGui.QAction(QtGui.QIcon(
 >iconPath), name, self)
605                voice.setShortcut(shortcut)
606                voice.setStatusTip(tip)
607                self.connect(voice, QtCore.SIGNAL(
 >'triggered()'), slot)
608                
609                return voice
610        
611        def createSeparator(self):
612                sVoice = QtGui.QAction(self)
613                sVoice.setSeparator(True)
614                
615                return sVoice
616        
617        def createMenu(self):
618                tinyMenu = self.menuBar()
619                
620                file = tinyMenu.addMenu("&File")
621                edit = tinyMenu.addMenu("&Edit")
622                font = tinyMenu.addMenu("F&ont")
623                
624                new = self.createMenuVoice("icons/
 >new.png", "New", "Ctrl+N", "New file", self.textEd
 >it.clear)
625                open = self.createMenuVoice("icons
 >/open.png", "Open file", "Ctrl+O", "Open a new fil
 >e", self.openNewFile)
626                save = self.createMenuVoice("icons
 >/save.png", "Save file", "Ctrl+S", "Save file", se
 >lf.saveNewFile)
627                sep = self.createSeparator()
628                quit = self.createMenuVoice("icons
 >/quit.png", "Quit", "Ctrl+Q", "Quit TinyEditor", Q
 >tCore.SLOT('close()'))
629                file.addAction(new)
630                file.addAction(open)
631                file.addAction(save)
632                file.addAction(sep)
633                file.addAction(quit)
634                
635                undo = self.createMenuVoice("icons
 >/undo.png", "Undo", "Ctrl+U", "Undo operation", se
 >lf.textEdit.undo)
636                redo = self.createMenuVoice("icons
 >/redo.png", "Redo", "Ctrl+R", "Redo operation", se
 >lf.textEdit.redo)
637                sep1 = self.createSeparator()
638                cut = self.createMenuVoice("icons/
 >cut.png", "Cut", "Ctrl+X", "Cut selected text", se
 >lf.textEdit.cut)
639                copy = self.createMenuVoice("icons
 >/copy.png", "Copy", "Ctrl+C", "Copy selected text"
 >, self.textEdit.copy)
640                paste = self.createMenuVoice("icon
 >s/paste.png", "Paste", "Ctrl+V", "Paste text", sel
 >f.paste)
641                sep2 = self.createSeparator()
642                selectAll = self.createMenuVoice("
 >icons/selectAll.png", "Select all", "Ctrl+A", "Sel
 >ect all text", self.textEdit.selectAll)
643                edit.addAction(undo)
644                edit.addAction(redo)
645                edit.addAction(sep1)
646                edit.addAction(cut)
647                edit.addAction(copy)
648                edit.addAction(paste)
649                edit.addAction(sep2)
650                edit.addAction(selectAll)
651                
652                setFont = self.createMenuVoice("ic
 >ons/setfont.png", "Set font", "Ctrl+F", "Set font"
 >, self.setFont)
653                underline = self.createMenuVoice("
 >icons/underline.png", "Underline", "Ctrl+L", "Unde
 >rline text", self.underline)
654                italic = self.createMenuVoice("ico
 >ns/italic.png", "Italic", "Ctrl+I", "Set text to i
 >talic", self.italic)
655                tColor = self.createMenuVoice("ico
 >ns/color.png", "Set text color", "Ctrl+R", "Set te
 >xt color", self.setColor)
656                delete = self.createMenuVoice("ico
 >ns/delete.png", "Delete format", "Ctrl+D", "Delete
 > format", self.deleteFormat)
657                font.addAction(setFont)
658                font.addAction(underline)
659                font.addAction(italic)
660                font.addAction(tColor)
661                font.addAction(delete)
662        
663        def __init__(self):
664                QtGui.QMainWindow.__init__(self)
665
666                self.setWindowTitle('Tiny editor')
 >
667                
668                self.textEdit = QtGui.QTextEdit()
669                self.textEdit.setReadOnly(False)
670                
671                if self.textEdit.isUndoRedoEnabled
 >() == False:
672                        self.textEdit.setUndoRedoE
 >nabled(True)
673                
674                self.createMenu()
675                self.statusBar()
676                self.setCentralWidget(self.textEdi
 >t)
677        
678        def openNewFile(self):
679                fName = QtGui.QFileDialog.getOpenF
 >ileName(self, "Open text file", "Open new file", s
 >elf.tr("Text Files (*.txt)"))
680                
681                if fName.isEmpty() == False:
682                        fptr = open(fName, 'r')
683                        
684                        content = fptr.read()
685                        self.textEdit.append(conte
 >nt)
686                        fptr.close()
687        
688        def saveNewFile(self):
689                fName = QtGui.QFileDialog.getSaveF
 >ileName(self, "Save text file", "Save a new file",
 > self.tr("Text Files (*.txt)"))
690                
691                if fName.isEmpty() == False:
692                        fptr = open(fName, 'w')
693                        
694                        fptr.write(self.textEdit.t
 >oPlainText())
695                        fptr.close()
696                        
697        def paste(self):
698                if self.textEdit.canPaste():
699                        self.textEdit.paste()
700                else:
701                        QtGui.QMessageBox.critical
 >(self, "Error", "Impossible to paste text", QtGui.
 >QMessageBox.Ok)
702
703                
704        def setFont(self):
705                font, ok = QtGui.QFontDialog.getFo
 >nt()
706                
707                if ok:
708                        self.textEdit.setFont(font
 >)
709        
710        def underline(self):
711                self.textEdit.setFontUnderline(Tru
 >e)
712                
713        def italic(self):
714                self.textEdit.setFontItalic(True)
715                
716        def setColor(self):
717                color = QtGui.QColorDialog.getColo
 >r(QtCore.Qt.blue, self)
718                
719                if color.isValid():
720                        self.textEdit.setTextColor
 >(color)
721                        
722        def deleteFormat(self):
723                self.textEdit.setFontUnderline(Fal
 >se)
724                self.textEdit.setFontItalic(False)
 >
725                self.textEdit.setTextColor(QtCore.
 >Qt.black)
726        
727  app = QtGui.QApplication(sys.argv)
728  main = MainWindow()
729  main.show()
730  sys.exit(app.exec_())
731
732.. img:: 14
733   :nolink:
734
735Il tutto è piuttosto intuitivo.
736Come notate, la maggior parte delle azioni tipiche
 > di un editor (taglia, copia, incolla, seleziona t
 >utto, annulla operazione...) non hanno bisogno di 
 >un'implementazione a parte del programmatore, ma c
 >i si può avvalere dei metodi predefiniti del widge
 >t.
737Come noterete, sono riapparsi anche precedenti dia
 >log predefiniti.
738Come esercizio potreste tentare di migliorare ques
 >to editor!
739
740GroupBox e SpinBox
741===================
742
743Vediamo altri due widgets utili:  GroupBox e  Spin
 >Box. Il primo serve a dividere diverse sezioni di 
 >programma tramite dei titoletti in “grassetto”, me
 >ntre la seconda è utile per l'input di dati numeri
 >ci.::
744
745  #!/usr/bin/python
746
747  import sys
748  from PyQt4 import QtGui, QtCore
749
750  class MainWindow(QtGui.QMainWindow):
751        def __init__(self):
752                QtGui.QMainWindow.__init__(self)
753
754                self.resize(350, 250)
755                self.setWindowTitle('GroupBox e Sp
 >inBox')
756                
757                widget = QtGui.QWidget(self)
758                
759                self.gBox = QtGui.QGroupBox("SpinB
 >oxes", widget)
760                self.gBox.setCheckable(True)
761                self.gBox.setChecked(True)
762                self.connect(self.gBox, QtCore.SIG
 >NAL('clicked()'), self.showSpin)
763                
764                self.iSpin = QtGui.QSpinBox(widget
 >)
765                self.iSpin.setRange(0, 100)
766                self.iSpin.setSuffix("%")
767                self.iSpin.setValue(50)
768                self.iSpin.setSingleStep(5)
769                
770                self.dSpin = QtGui.QDoubleSpinBox(
 >widget)
771                self.dSpin.setDecimals(3)
772                self.dSpin.setPrefix("$")
773                self.dSpin.setRange(0, 1000.0)
774                self.dSpin.setSingleStep(0.5)
775                self.dSpin.setValue(100)
776                
777                vBox = QtGui.QVBoxLayout(widget)
778                vBox.setSpacing(3)
779                
780                vBox.addWidget(self.iSpin)
781                vBox.addWidget(self.dSpin)
782                
783                widget.setLayout(vBox)
784                self.setCentralWidget(widget)
785        
786        def showSpin(self):
787                if self.gBox.isChecked():
788                        self.dSpin.show()
789                        self.iSpin.show()
790                else:
791                        self.dSpin.hide()
792                        self.iSpin.hide()
793
794  app = QtGui.QApplication(sys.argv)
795  main = MainWindow()
796  main.show()
797  sys.exit(app.exec_())
798
799.. img:: 11
800   :nolink:
801
802In questo caso, associamo alla GroupBox una checkb
 >ox che ci permette di decidere fra due comportamen
 >ti. In realtà una GroupBox di default appare solo 
 >come un titoletto in grassetto, senza alcuna check
 >box. Quando si cambia lo stato della checkbox vien
 >e emesso un segnale *clicked()*.::
803
804                if self.gBox.isChecked():
805
806Se questo metodo ritorna True, la checkbox è stata
 > attivata, altrimenti è stata disattivata.
807Come vediamo, esistono due principali tipi di spin
 >box: la classica *QSpinBox*, che contiene interi, 
 >e la *QDoubleSpinBox*, che contiene valori double.
 >
808È possibile specificare un range di valori accetta
 >bili, un valore di default, il “salto” fra due val
 >ori contigui, e stringhe da usare come suffissi o 
 >prefissi dei valori numerici.
809
810ProgressBar
811============
812Esempio di utilizzo di una barra di avanzamento.::
 >
813
814  #!/usr/bin/python
815
816  import sys
817  from PyQt4 import QtGui, QtCore
818
819  class MainWindow(QtGui.QMainWindow):
820        def __init__(self):
821                QtGui.QMainWindow.__init__(self)
822
823                self.resize(350, 250)
824                self.setWindowTitle('ProgressBar')
 >
825                widget = QtGui.QWidget()
826                
827                grid = QtGui.QGridLayout(widget)
828                self.progressBar = QtGui.QProgress
 >Bar(widget)
829                self.progressBar.setRange(0, 100)
830                self.progressBar.setValue(0)
831                self.progressBar.setTextVisible(Tr
 >ue)
832                
833                self.button = QtGui.QPushButton('S
 >tart', widget)
834                self.connect(self.button, QtCore.S
 >IGNAL('clicked()'), self.StartProgress)
835                
836                self.horiz = QtGui.QPushButton('Ve
 >rtical', widget)
837                self.horiz.setCheckable(True)
838                self.connect(self.horiz, QtCore.SI
 >GNAL('clicked()'), self.changeOrientation)
839                
840                self.direction = QtGui.QPushButton
 >('Reverse', widget)
841                self.direction.setCheckable(True)
842                self.connect(self.direction, QtCor
 >e.SIGNAL('clicked()'), self.Reverse)
843                
844                grid.addWidget(self.progressBar, 0
 >, 0, 1, 3)
845                grid.addWidget(self.button, 1, 0)
846                grid.addWidget(self.horiz, 1, 1)
847                grid.addWidget(self.direction, 1, 
 >2)
848                
849                self.timer = QtCore.QBasicTimer()
850                self.step = 0
851                
852                widget.setLayout(grid)
853                self.setCentralWidget(widget)
854        
855        def Reverse(self):
856                if self.direction.isChecked():
857                        self.progressBar.setInvert
 >edAppearance(True)
858                else:
859                        self.progressBar.setInvert
 >edAppearance(False)
860        
861        def changeOrientation(self):
862                if self.horiz.isChecked():
863                        self.progressBar.setOrient
 >ation(QtCore.Qt.Vertical)
864                else:
865                        self.progressBar.setOrient
 >ation(QtCore.Qt.Horizontal)
866        
867        def timerEvent(self, event):
868                if self.step >= 100:
869                        self.timer.stop()
870                        return
871                self.step = self.step+1
872                self.progressBar.setValue(self.ste
 >p)
873        
874        def StartProgress(self):
875                if self.timer.isActive():
876                        self.timer.stop()
877                        self.button.setText('Start
 >')
878                else:
879                        self.timer.start(100, self
 >)
880                        self.button.setText('Stop'
 >)
881                
882  app = QtGui.QApplication(sys.argv)
883  main = MainWindow()
884  main.show()
885  sys.exit(app.exec_())
886
887.. img:: 13
888   :nolink:
889
890La dichiarazione della progress bar è questa:::
891
892                self.progressBar = QtGui.QProgress
 >Bar(widget)
893                self.progressBar.setRange(0, 100)
894                self.progressBar.setValue(0)
895                self.progressBar.setTextVisible(Tr
 >ue)
896
897Nota: i tre metodi che chiamo dopo il costruttore 
 >in realtà potrebbero essere omessi, in quanto quel
 >li specificati sono già i comportamenti di default
 >. Li ho inseriti solamente a scopo dimostrativo.::
 >
898
899                self.timer = QtCore.QBasicTimer()
900                self.step = 0
901
902Qui dichiariamo un timer, un oggetto di basso live
 >llo molto semplice e adatto alle nostre esigenze. 
 >Ogni tot millisecondi (il valore precisato nel met
 >odo *start()*), il timer genera un evento che noi 
 >intercettiamo con la nostra funzione. Ogni 100 mil
 >lisecondi dunque avanziamo di 1 nella progress bar
 >.
903Se vogliamo che essa sia più veloce, dobbiamo ovvi
 >amente diminuire il valore numerico passato a *sta
 >rt()*.
904Le due funzioni importanti sono *Reverse* e *chang
 >eOrientation*: essi, a seconda del valore del togg
 >le button corrispondente, “rovesciano” il testo de
 >lla progress bar oppure il suo orientamento.
905
906Tooltip, password e combo box
907==============================
908
909Finiamo con tre widget.::
910
911  #!/usr/bin/python
912
913  import sys
914  from PyQt4 import QtGui, QtCore
915
916  class MainWindow(QtGui.QMainWindow):
917        def __init__(self):
918                QtGui.QMainWindow.__init__(self)
919
920                self.resize(350, 250)
921                self.setWindowTitle('Tooltip e pas
 >sword')
922                widget = QtGui.QWidget()
923                hbox = QtGui.QHBoxLayout(widget)
924                hbox.setSpacing(10)
925
926                self.label = QtGui.QLabel("Enter y
 >our username", widget)
927                self.line = QtGui.QLineEdit(widget
 >)
928                comboBox = QtGui.QComboBox()
929                comboBox.addItem("Username")
930                comboBox.addItem("Password")
931                self.connect(comboBox, QtCore.SIGN
 >AL("activated(int)"), self.changeEcho)
932                
933                hbox.addWidget(self.label)
934                hbox.addWidget(self.line)
935                hbox.addWidget(comboBox)        
936                self.setToolTip('This is a tooltip
 >')
937                self.setCentralWidget(widget)
938        
939        def changeEcho(self, index):
940                if index == 0:
941                        self.line.setEchoMode(QtGu
 >i.QLineEdit.Normal)
942                        self.label.setText("Enter 
 >your username")
943                else:
944                        self.line.setEchoMode(QtGu
 >i.QLineEdit.Password)
945                        self.label.setText("Enter 
 >your password")
946
947  app = QtGui.QApplication(sys.argv)
948  main = MainWindow()
949  main.show()
950  sys.exit(app.exec_())
951
952.. img:: 16
953   :nolink:
954
955Il widget *QLineEdit* è comodo per inserire piccol
 >e porzioni di testo. Se vogliamo una maggiore sicu
 >rezza possiamo anche impostare il tipo di “echo” a
 > password, come viene fatto nello slot.
956La *combo box* permette all'utente di scegliere di
 >verse opzioni: la selezione è catturata dal segnal
 >e *activated()*, che manda al proprio slot un para
 >metro intero, ovvero l'indice della voce momentane
 >amente attivata.
957Il tooltip può essere visto soffermando il cursore
 > su un punto qualsiasi della finestra.
958
959Conclusioni.
960#############
961
962Se avete qualsiasi suggerimento, correzione ai cod
 >ici, miglioria che volete vedere in questo tutoria
 >l, scrivetemi pure a syn.shainer@gmail.com
963Lisa