TI/Programowanie dla Fizyków Medycznych:Galeria Widgetow: Różnice pomiędzy wersjami

Z Brain-wiki
(Utworzono nową stronę "W tym rozdziale zaprezentuję krótko widgety dostępne w wxPythonie, związane z nimi style i eventy. ==Wyświetlanie tekstu== Do wyświetlania tekstu stosuje się obie...")
 
 
(Nie pokazano 1 wersji utworzonej przez jednego użytkownika)
Linia 254: Linia 254:
 
app.MainLoop()
 
app.MainLoop()
 
</source>
 
</source>
[[category:Programowanie dla Fizyków Medycznych]]
+
 
 +
[["Programowanie dla Fizyków Medycznych"]]

Aktualna wersja na dzień 11:25, 4 cze 2015

W tym rozdziale zaprezentuję krótko widgety dostępne w wxPythonie, związane z nimi style i eventy.

Wyświetlanie tekstu

Do wyświetlania tekstu stosuje się obiekty klasy wx.StaticText. Można ustawiać kolor tekstu (metoda SetForegroundColour) i rodzaj czcionki (metoda SetFont). Konstruktor opisywanej klasy wygląda następująco:

wx.StaticText(parent, id, label, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, name="staticText")

Konstruktory większości widgetów w wxPythonie są podobne - na pierwszym koniecznym parametrze przekazywany jest rodzic czyli kontener w którym ma być wyświetlany tworzony obiekt, następne parametry są opcjonalne: id - numer identyfikacyjny przypisywany obiektowi, jeśli nie podamy nic, podamy -1 lub wx.ID_ANY to Python sam przypisze numer id tak aby był on unikalny na poziomie kontenera (jeśli numery id podajemy sami to powinny być one dodatnie i unikalne na poziomie kontenera), dalej występuje parametr label mówiący co ma być wypisane na ekranie, następnie dwie krotki opisują pozycję widgetu we współrzędnych ramki i jego wielkość, liczba całkowita (style) opisująca w formie maski bitowej styl (możliwe wartości to wx.ALIGN_CENTER, wx.ALIGN_RIGHT, wx.ALIGN_LEFT - do ustawiania tekstu wewnątrz widgetu i wx.ST_NO_AUTORESIZE - do wyłączania zmieniania rozmiaru widgetu po wywołaniu SetLabel) i na koniec można podać parametr name czyli nazwę po której będziemy mogli później znaleźć tworzony obiekt.

# -*- coding: utf-8 -*-
import wx

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        panel = wx.Panel(self)
        txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "przykładowy tekst", pos = (0, 0), size = (100, 200), style = 0, name = 'tekst')
        txt.SetForegroundColour('red')
        font = wx.Font(18, wx.DECORATIVE, wx.ITALIC, wx.NORMAL)
        txt.SetFont(font)
        self.Show()

app = wx.App()
MyFrame()
app.MainLoop()

Przy pomocy metody SetLabel(self, string) można ustawić zawartość okna, a pobrać ją metodą GetLabel(self)

Wprowadzanie tekstu

Do wprowadzania tekstu służą obiekty klasy wx.TextCtrl, wpisywany tekst może być ukrywany jako hasło. Konstruktor tej klasy wygląda następująco:

wx.TextCtrl(parent, id, value = "", pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0, validator = wx.DefaultValidator, name = wx.TextCtrlNameStr)

W stosunku do poprzedniego obiektu parametr label został zastąpiony parametrem value (również metody pobierające i ustawiające będą się nazywały SetValue(self, string) i GetValue(self)). Validatory służą do sprawdzania czy podane przez użytkownika dane są poprawne - zostaną one opisane w oddzielnym rozdziale. W tym przypadku możliwe style są inne: do zarządzania pozycją wpisanego tekstu służą style wx.TE_CENTER, wx.TE_LEFT, wx.TE_RIGHT, do maskowania wpisywanego tekstu jako hasło wx.TE_PASSWORD, aby uniemożliwić wpisywanie do danego widgeta należy podać styl wx.TE_READONLY, w końcu występują dwa style opisujące działanie związane z wciśnięciem klawisza enter lub tab gdy jesteśmy w okienku, gdy podamy styl wx.TE_PROCESS_ENTER po wciśnięciu klawisza enter zostanie zgłoszony event wx.EVT_TEXT_ENTER, a ustawienie stylu wx.TE_PROCESS_TAB spowoduje, że wciśnięcie taba podczas wpisywania do widgeta spowoduje wprowadzenie tabulatora do tekstu zamiast standardowego przechodzenia focusem do kolejnego okienka. Gdy do wx.TextCtrl zostanie wprowadzony tekst jest generowany event wx.EVT_TEXT. Metodą AppendText(string) można dodać tekst do już wpisanego (na koniec, na początek dodaje się metodą WriteText(string)), Clear() powoduje czyszczenie okna, GetRange(from, to) zwraca tekst znajdujący się na pozycjach od from do to, GetSelection() zwraca krotkę z początkowym i końcowym indeksem zaznaczenia, GetStringSelection() zwraca zaznaczenie jako napis, a SetSelection(from, to) zaznacza tekst na pozycjach od from do to. Metody GetValue() i SetValue(string) zwracają i ustawiają cały napis. Tekst można usuwać metodą Remove(from, to) i zamieniać na inny napis metodą Replace(from, to, string). Prosty przykład:

# -*- coding: utf-8 -*-
import wx

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        panel = wx.Panel(self)
        txt = wx.TextCtrl(parent = panel, id = 11, value = u"przykladowy tekst", size = (200, 50), style = wx.TE_PROCESS_ENTER)
        self.Bind(wx.EVT_TEXT, self.OnText, txt)
        self.Bind(wx.EVT_TEXT_ENTER, self.OnTextEnter, txt)
        self.Show()
    def OnText(self, evt):
        wx.MessageBox(u"Zmienione tekst, aktualna wartość: " + self.FindWindowById(evt.GetId()).GetValue())
    def OnTextEnter(self, evt):
        wx.MessageBox(u"Wciśnięto klawisz enter")
app = wx.App()
MyFrame()
app.MainLoop()

Widgety można wyszukiwać także po nazwie metodą FindWindowByName i po labelce jeśli ją posiadają metodą FindWidnowByLabel.

Przyciski

Przyciski w wxPythonie to obiekty klasy wx.Button, konstruktor tej klasy wygląda następująco:

wx.Button(parent, id, label, pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0, validator = wx.DefaultValidator, name = "button")

Przycisk po kliknięciu go wysyła event wx.EVT_BUTTON. Prosty przykład użycia:

# -*- coding: utf-8 -*-
import wx

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        panel = wx.Panel(self)
        btn = wx.Button(panel, label = u"przykladowy tekst")
        self.Bind(wx.EVT_BUTTON, self.OnButton, btn)
        self.Show()
    def OnButton(self, evt):
        wx.MessageBox(u"Wciśnięto przycisk")
        
app = wx.App()
MyFrame()
app.MainLoop()

Innym rodzajem przycisku jest wx.ToggleButton, który ma dwa stany wciśnięty lub nie - działa podobnie jak checkbox, jego stan można pobrać przy pomocy GetValue, a ustawić SetValue, wysyła on też inne event po przyciśnięci - patrz przykład:

# -*- coding: utf-8 -*-
import wx

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        panel = wx.Panel(self)
        btn = wx.ToggleButton(panel, label = u"przykladowy tekst")
        self.Bind(wx.EVT_TOGGLEBUTTON, self.OnButton, btn)
        self.Show()
    def OnButton(self, evt):
        wx.MessageBox(u"Przycisk " + (u"wciśnięty" if self.FindWindowById(evt.GetId()).GetValue() else u"nie wciśnięty"))
        
app = wx.App()
MyFrame()
app.MainLoop()

Suwaki

Do pobierania od użytkownika danych, które musi wpisać są liczbami całkowitymi z pewnego przedziału można wykorzystać suwaki reprezentowane przez klasę wx.Slider. Konstruktor tej klasy wygląda następująco:

wx.Slider(parent, id, value, minValue, maxValue, pos = wxDefaultPosition, size = wx.DefaultSize, style = wx.SL_HORIZONTAL, validator = wx.DefaultValidator, name = "slider")

Parametr value oznacza początkową wartość suwaka, a jego zakres jest określany przez minValue i maxValue. Dostępne są następujące style: wx.SL_HORIZONTAL i wx.SL_VERTICAL ustawiające kierunek suwaków, wx.SL_LEFT, wx.SL_RIGHT,i wx.SL_TOP - określające gdzie należy narysować kreseczki oznaczające kolejne wartości, podanie stylu wx.SL_LABELS powoduje pojawienie się informacji jaka jest największa, najmniejsza i aktualnie zaznaczona wartość i wx.SL_AUTOTICKS, którego ustawienie powoduje pojawienie się kreseczek, których gęstość można ustawić metodą SetTickFreq(n, pos) - gdzie n to wartość kroku między kreseczkami, a drugi parametr nie jest używany. Do pobierania i ustawiania zakresu służą metody GetRange() i SetRange(min, max). Gdy focus jest na sliderze, to jego wartość można zmieniać przy pomocy strzałek - o ile wartość jest wtedy zmieniana można ustawić metodą SetLineSize(n) i pobrać GetLineSize(), a także przy pomocy klawiszy PgUp i PgDn - odpowiednie metody to: SetPageSize(n) i GetPageSize(). W końcu pobrać i ustawić wartość można przy pomocy GetValue() i SetValue(n). Eventy generowane przez tą klasę to EVT_SCROLL, EVT_SCROLL_BOTTOM i EVT_SCROLL_TOP generowane gdy użytkownik przesunie slider do odpowiedniego końca, EVT_SCROLL_LINEDOWN, EVT_SCROLL_LINEUP, EVT_SCROLL_PAGEDOWN, EVT_SCROLL_PAGEUP generowane gdy użytkownik zmienia wartość slidera przy pomocy klawiszy, EVT_SCROLL_THUMBRELEASE, EVT_SCROLL_THUMBTRACK - generowane gdy zakończymy przesuwanie slidera i podczas przesuwania. Przykład:

# -*- coding: utf-8 -*-
import wx

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        panel = wx.Panel(self)
        btn = wx.Slider(panel, minValue = 0, maxValue = 200, value = 100, size = (200, 50), style = wx.SL_HORIZONTAL|wx.SL_LABELS|wx.SL_TOP)
        self.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnThumbRelease, btn)
        self.Show()
    def OnThumbRelease(self, evt):
        wx.MessageBox(u"Przesuwanie zakończone warość " + str(self.FindWindowById(evt.GetId()).GetValue()))
        
app = wx.App()
MyFrame()
app.MainLoop()

Spinner

Spinner pozwala ustawiać wartości z pewnego dyskretnego zakresu przy pomocy strzałek i pola typu TextCtrl, konstruktor wygląda następująco:

wx.SpinCtrl(parent, id = -1, value = wx.EmptyString, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.SP_ARROW_KEYS, min = 0, max = 100, initial = 0, name = "wxSpinCtrl")

Gdy wartość zostanie zmieniona generowany jest event EVT_SPINCTRL, jeśli zmieniany jest tekst w TextCtrl to generowany jest EVT_TEXT, styl wx.SP_ARROW_KEYS pozwala na zmienianie wartości przy pomocy strzałek do góry i dół, a wx.SP_WRAP powoduje, że po osiągnięciu maksymalnej wartości przechodzimy do wartości najmniejszych. Prosty przykład:

# -*- coding: utf-8 -*-
import wx

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        panel = wx.Panel(self)
        spin = wx.SpinCtrl(panel, min = 0, max = 200, initial = 100, style = wx.SP_ARROW_KEYS|wx.SP_WRAP)
        self.Bind(wx.EVT_SPINCTRL, self.OnSpin, spin)
        self.Bind(wx.EVT_TEXT, self.OnText, spin)
        self.Show()
    def OnSpin(self, evt):
        wx.MessageBox(u"Zmieniono warość na " + str(self.FindWindowById(evt.GetId()).GetValue()))
    def OnText(self, evt):
        wx.MessageBox(u"Wpisano coś do TextCtrl")
        
app = wx.App()
MyFrame()
app.MainLoop()

CheckBoxy

CheckBoxy pozwalają wybrać użytkownikowi pewne opcje, mają one dwa stany - zaznaczony i nie zaznaczony. Konstruktory wygląda następująco:

wx.CheckBox(parent, id, label, pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0, name = "checkBox")

Przy zmianie stanu zgłaszany jest event EVT_CHECKBOX. Klasa wx.CheckBox udostępnia metody GetValue, SetValue i IsChecked. Przykład:

# -*- coding: utf-8 -*-
import wx

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        panel = wx.Panel(self)
        for i in range(5):
            wx.CheckBox(panel, label = 'Opcja ' + str(i), id = 100 + i, pos = (0, 25 * i))
        self.Bind(wx.EVT_CHECKBOX, self.OnCheck, id = 100, id2 = 104)
        self.Show()
    def OnCheck(self, evt):
        win = self.FindWindowById(evt.GetId())
        wx.MessageBox(win.GetLabel() + u' została ' + ('zaznaczona' if win.IsChecked() else 'odznaczona'))
        
app = wx.App()
MyFrame()
app.MainLoop()

RadioButtony

Jeśli chcemy aby użytkownik wybrał dokładnie jedną z niewielkiej liczby opcji można to zrealizować za pomocą RadioButtonów połączonych w grupę, konstruktor opisywanej klasy jest następujący:

wx.RadioButton(parent, id, label, pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0, validator = wx.DefaultValidator, name = "radioButton")
<source>
Utworzenie obiektu o stylu wx.RB_GROUP rozpoczyna nową grupę i wszystkie utworzone obiekty do czasu kolejnego z takim stylem będą należały do jednej grupy, a więc dokładnie jeden z nich będzie wybrany. Przy zmianie stanu na zaznaczony generowany jest event EVT_RADIOBUTTON. Przykład zastosowania:
<source lang='python'>
# -*- coding: utf-8 -*-
import wx

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        panel = wx.Panel(self)
        for i in range(5):
            wx.RadioButton(panel, label = 'Opcja ' + str(i), id = 100 + i, pos = (0, 25 * i))
        self.Bind(wx.EVT_RADIOBUTTON, self.OnCheck, id = 100, id2 = 104)
        self.Show()
    def OnCheck(self, evt):
        win = evt.GetEventObject()
        wx.MessageBox(win.GetLabel() + u' została zaznaczona')
        
app = wx.App()
MyFrame()
app.MainLoop()

Ten przykład pokazuje przy okazji, że z eventu można bezposrednio uzyskać obiekt który go wygenerował przy pomocy metody GetEventObject(). Do sprawdzania stanu radioboxa można wykorzystać metodę GetValue()

ListBoxy

ListBoxy są stosowane jeśli użytkownik może wybrać jedną lub więcej opcji z podanej listy. Konstruktor wygląda następująco:

wx.ListBox(parent, id, pos = wx.DefaultPosition, size = wx.DefaultSize, choices = None, style = 0, validator = wx.DefaultValidator, name = "listBox")

Na paramer choices podajemy listę opcji z których użytkownik może wybierać. Styl wx.LB_SINGLE dopuszcza tylko pojedynczy wybór, wx.LB_MULTIPLE wybranie wielu opcji, a wx.LB_EXTENDED wybór wielu opcji ale następujących po sobie przy pomocy klikania z wciśniętym klawiszem shift. ListBox może być wyposażony w scrollbar, jego występowanie opisują następujące style: wx.LB_ALWAYS_SB - zawsze jest wyświetlany, wx.LB_HSCROLL - pojawia się poziomy scroll, wx.LB_NEEDED_SB - domyślny styl, pioinowy scrollbar pojawia się tylko gdy jest potrzebny, styl wx.LB_SORT powoduje, że wyświetlana lista opcji jest posortowana alfabetycznie. Kiedy element na liście zostaje wybrany zgłaszany jest event EVT_LISTBOX, a po dwukrotnym kliknięciu na listę EVT_LISTBOX_DCLICK. Opisywana klasa udostępnia metody do dodawania, usuwania i pobierania opcji z listy: Append(item), Clear(), Delete(n), GetCount(), InsertItems(items, pos) i Set(choices), a także do ustawiania i pobierania elementów zaznaczonych: GetSelection(), SetSelection(n, select), GetStringSelection(), SetStringSelection(string, select), GetSelections(), Deselect(n) i Selected(n) - ich nazwy dość jasno mówią co dane metody robią. Prosty przykład:

# -*- coding: utf-8 -*-
import wx
import string

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        panel = wx.Panel(self)
        self.last = 'A'
        self.listBox = wx.ListBox(panel, choices = [self.last], size = (-1, 100), style = wx.LB_MULTIPLE)
        self.Bind(wx.EVT_LISTBOX, self.OnList, self.listBox)
        self.Show()
    def OnList(self, evt):
        win = evt.GetEventObject()
        opcje = [win.GetString(index) for index in win.GetSelections()]
        wx.MessageBox(u'zaznaczone opcje : ' + string.join(opcje))
        self.last = chr(ord(self.last) + 1)
        self.listBox.Append(self.last)
app = wx.App()
MyFrame()
app.MainLoop()

Listy rozwijane

W wxPythonie są dwa rodzaje list rozwijanych - wx.Choice pozwalająca wybrać opcję z podanych i wx.ComboBox dodatkowo pozwalająca wpisać dowolną wartość, ich konstruktory to:

wx.Choice(parent, id, pos = wx.DefaultPosition, size = wx.DefaultSize, choices = wx.EmptyList, style = 0, validator = wx.DefaultValidator, name = "choice")
wx.ComboBox(parent, id, value = "", pos = wx.DefaultPosition, size = wx.DefaultSize, choices = wx.EmptyList, style = 0, validator = wx.DefaultValidator, name = "comboBox")

W przeciwieństwie do obiektów klasy wx.Choice obiektom klasy wx.ComboBox można ustawić wartość początkową (obiekty wx.Choice mają na początku pustą wartość). Gdy opcja zostanie wybrana obiekty generują odpowiednio eventy: EVT_CHOICE i EVT_COMBOBOX. Jeśli utworzymy ComboBoxa ze stylem wx.CB_READONLY nie można będzie wprowadzać własnych opcji, a ze stylem wx.CB_SORT powoduje, że elementy na liście będą posortowane alfabetycznie. Prosty przykład:

# -*- coding: utf-8 -*-
import wx
import string

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        panel = wx.Panel(self)
        comboBox = wx.ComboBox(panel, choices = ['A', 'B', 'C'], size = (-1, 100))
        self.Bind(wx.EVT_COMBOBOX, self.OnCombo, comboBox)
        self.Bind(wx.EVT_TEXT, self.OnCombo, comboBox)
        self.Show()
    def OnCombo(self, evt):
        wx.MessageBox(u'wybrana opcja : ' + evt.GetEventObject().GetValue())
app = wx.App()
MyFrame()
app.MainLoop()

"Programowanie dla Fizyków Medycznych"