TI/Programowanie dla Fizyków Medycznych:Dialogi

Z Brain-wiki
Wersja z dnia 11:27, 4 cze 2015 autorstwa Tgubiec (dyskusja | edycje)
(różn.) ← poprzednia wersja | przejdź do aktualnej wersji (różn.) | następna wersja → (różn.)

Dialogi

W tym rozdziale opiszę obiekty klasy wx.Dialog, są one bardzo podobne do obiektów klasy wx.Frame, a najważniejsze różnice to:

  • dialogi są przeznaczone do komunikowania czegoś użytkownikowi lub pobierania małych porcji informacji od niego, zazwyczaj są wyświetlane znacznie krócej niż ramki
  • dialogi zazwyczaj są wyświetlane w trybie modal co oznacza, że są jedynym aktywnym oknem naszej aplikacji, zanim dialog nie zostanie zamknięty program nie będzie reagował na żadne eventy związane z innymi oknami
  • dialogi po zamknięciu nie są automatycznie niszczone, gdyż często konieczne jest pobranie z nich informacji po zamknięciu, z drugiej strony są one oknami najwyższego poziomu, a więc należy je zniszczyć aby aplikacja wxPythona się zakończyła
  • wxPython dostarcza kilku przydatnych dialogów systemowych: do wysyłania informacji, pytania tak/nie, pobierania pojedynczego tekstu lub hasła, wybierania jednej lub kilku z podanych opcji, wybierania pliku do zapisu/odczytu, wybierania katalogu, wybierania koloru i czcionki, a także prezentowania paska postępu - poza trzema ostatnimi wszystkie zostaną zaprezentowane w tym rozdziale

Dostarczone przez wxPythona dialogi można tworzyć na dwa sposoby - za pomocą konstruktora odpowiedniej klasy, a następnie wyświetlić metodą ShowModal() lub użyć funkcji tworzącej i wyświetlającej okno. Metoda ShowModal() zwraca stałą z wxPythona wskazującą, którym przyciskiem zamknięto okno (wx.ID_OK, wx.ID_CANCEL, wx.ID_NO, wx.ID_YES), z kolei wynik odpowiednich funkcji zależy od tego jakie okienko zostało wyświetlone. Oto przykłady:

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

class MyFrame(wx.Frame):
    def __init__(self):
        super(MyFrame, self).__init__(None)
        self.InitUI()
        self.Show()
    def InitUI(self):
        klasy = ['wx.MessageDialog', 'wx.TextEntryDialog', 'wx.SingleChoiceDialog', 'wx.FileDialog', 'wx.DirDialog']
        funkcje = ['wx.MessageBox', 'wx.GetTextFromUser', 'wx.GetPasswordFromUser', 'wx.GetNumberFromUser', 'wx.GetSingleChoiceIndex', 'wx.GetSingleChoice', 'wx.FileSelector', 'wx.DirSelector']
        panel = wx.Panel(self)
        sizerKlasy = wx.StaticBoxSizer(wx.StaticBox(panel, label = 'klasy'), wx.VERTICAL)
        for id, label in enumerate(klasy):
            sizerKlasy.Add(wx.Button(panel, id + 100, label), proportion = 1, flag = wx.EXPAND)
        sizerFunkcje = wx.StaticBoxSizer(wx.StaticBox(panel, label = 'funkcje'), wx.VERTICAL)
        for id, label in enumerate(funkcje):
            sizerFunkcje.Add(wx.Button(panel, id + 200, label), proportion = 1, flag = wx.EXPAND)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(sizerKlasy, proportion = 1)
        sizer.Add(sizerFunkcje, proportion = 1)
        sizer.Fit(panel)
        panel.SetSizer(sizer)
        self.Bind(wx.EVT_BUTTON, self.OnMessageDialog, id = 100)
        self.Bind(wx.EVT_BUTTON, self.OnTextEntryDialog, id = 101)
        self.Bind(wx.EVT_BUTTON, self.OnSingleChoiceDialog, id = 102)
        self.Bind(wx.EVT_BUTTON, self.OnFileDialog, id = 103)
        self.Bind(wx.EVT_BUTTON, self.OnDirDialog, id = 104)
        self.Bind(wx.EVT_BUTTON, self.OnMessageBox, id = 200)
        self.Bind(wx.EVT_BUTTON, self.OnGetTextFromUser, id = 201)
        self.Bind(wx.EVT_BUTTON, self.OnGetPasswordFromUser, id = 202)
        self.Bind(wx.EVT_BUTTON, self.OnGetNumberFromUser, id = 203)
        self.Bind(wx.EVT_BUTTON, self.OnGetSingleChoiceIndex, id = 204)
        self.Bind(wx.EVT_BUTTON, self.OnGetSingleChoice, id = 205)
        self.Bind(wx.EVT_BUTTON, self.OnFileSelector, id = 206)
        self.Bind(wx.EVT_BUTTON, self.OnDirSelector, id = 207)
    def OnMessageDialog(self, evt):
        dlg = wx.MessageDialog(None, u'Czy podoba Ci się wxPython?', u'Pytanie', wx.YES_NO|wx.ICON_QUESTION)
        if dlg.ShowModal() == wx.ID_YES:
            print u'to dobrze'
        else:
            print u'szkoda'
        dlg.Destroy()
    def OnTextEntryDialog(self, evt):
        dlg = wx.TextEntryDialog(None, u'Co najbardziej lubisz w wxPythonie?', u'Pytanie', '', wx.OK|wx.CANCEL)
        if dlg.ShowModal() == wx.ID_OK:
            print u'Twoja odpowiedź : ' + dlg.GetValue()
        else:
            print u'nie udzieliłeś odpowiedzi'
        dlg.Destroy()
    def OnSingleChoiceDialog(self, evt):
        dlg = wx.SingleChoiceDialog(None, u'Jaki sizer stosujesz najczęściej?', u'Pytanie', ['GridSizer', 'FlexGridSizer', 'GridBagSizer', 'StaticBoxSizer', 'BoxSizer'])
        if dlg.ShowModal() == wx.ID_OK:
            print u'wybrałeś : ' + dlg.GetStringSelection() + u' czyli opcję o indeksie ' + str(dlg.GetSelection())
        else:
            print u'nie udzieliłeś odpowiedzi'
        dlg.Destroy()      
    def OnFileDialog(self, evt):
        wildcard = u"Źródła Pythona (*.py)|*.py|Wszystkie pliki (*.*)|*.*"
        dlg = wx.FileDialog(None, u'Wybierz plik', os.getcwd(), '', wildcard, wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            print u'wybrałeś : ' + dlg.GetPath()
        else:
            print u'nie udzieliłeś odpowiedzi'
        dlg.Destroy()         
    def OnDirDialog(self, evt):
        dlg = wx.DirDialog(None, u'Wybierz katalog?', style = wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON)
        if dlg.ShowModal() == wx.ID_OK:
            print u'wybrałeś : ' + dlg.GetPath()
        else:
            print u'nie udzieliłeś odpowiedzi'
        dlg.Destroy()       
    def OnMessageBox(self, evt):
        if wx.MessageBox(u'Czy podoba Ci się wxPython?', u'Pytanie', wx.YES_NO|wx.ICON_QUESTION) == wx.ID_YES:
            print u'to dobrze'
        else:
            print u'szkoda'
    def OnGetTextFromUser(self, evt):
        answer = wx.GetTextFromUser(u'Co najbardziej lubisz w wxPythonie?', u'Pytanie', '')
        if answer != '':
            print u'Twoja odpowiedź : ' + answer
        else:
            print u'nie udzieliłeś odpowiedzi'
    def OnGetPasswordFromUser(self, evt):
        password = wx.GetPasswordFromUser(u'Podaj hasło', u'Hasło', '')
        if passwor != '':
            print u'Twoje hasło : ' + password
        else:
            print u'nie udzieliłeś odpowiedzi'
    def OnGetNumberFromUser(self, evt):
        number = wx.GetNumberFromUser(u'Podaj liczbę', u'Liczba:', u'Liczba', 50, 0, 100)
        if number != -1:
            print u'podana przez Ciebie liczba to ' + str(number)
        else:
            print u'podałeś nieprawidłową liczbę, albo nie podałeś liczby'
    def OnGetSingleChoiceIndex(self, evt):
        choiceIndex = wx.GetSingleChoiceIndex(u'Jaki sizer stosujesz najczęściej?', u'Pytanie', ['GridSizer', 'FlexGridSizer', 'GridBagSizer', 'StaticBoxSizer', 'BoxSizer'])
        if choiceIndex != -1:
            print u'wybrałeś : opcję o indeksie ' + str(choiceIndex)
        else:
            print u'nie udzieliłeś odpowiedzi'
    def OnGetSingleChoice(self, evt):
        choice = wx.GetSingleChoice(u'Jaki sizer stosujesz najczęściej?', u'Pytanie', ['GridSizer', 'FlexGridSizer', 'GridBagSizer', 'StaticBoxSizer', 'BoxSizer'])
        if choice != '':
            print u'wybrałeś : opcję ' + choice
        else:
            print u'nie udzieliłeś odpowiedzi'
    def OnFileSelector(self, evt):
        wildcard = u"Źródła Pythona (*.py)|*.py|Wszystkie pliki (*.*)|*.*"
        path = wx.FileSelector(u'Wybierz plik', os.getcwd(), '', '', wildcard, wx.OPEN)
        if dlg.ShowModal() != '':
            print u'wybrałeś : ' + path
        else:
            print u'nie udzieliłeś odpowiedzi'
    def OnDirSelector(self, evt):
        path = wx.DirSelector(u'Wybierz katalog?', '', style = wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON)
        if path != '':
            print u'wybrałeś : ' + path
        else:
            print u'nie udzieliłeś odpowiedzi'
            
app = wx.App()
MyFrame()
app.MainLoop()

wx.MessageDialog i wx.MessageBox może przyjmować następujące style manipulujące przyciskami wx.CANCEL, wx.OK, wx.YES_NO - powodują wyświetlenie odpowiednich przycisków, wx.NO_DEFAULT, wx.YES_DEFAULT - ustawiają domyślny klawisz gdy jest już użyty styl wx.YES_NO i style zmieniające wyświetlany obrazek: wx.ICON_ERROR, wx.ICON_EXCLAMATION, wx.ICON_INFORMATION, wx.ICON_QUESTION, ostatni możliwy styl to wx.STAY_ON_TOP powodujący, że okienko będzie zawsze na wierzchu nad wszystkimi oknami systemowymi. W tym przypadku metoda ShowDialog i odpowiednia funkcja zwracają jedną z wartości wx.ID_OK, wx.ID_YES, wx.ID_NO albo wx.ID_CANCEL - zależnie jaki przycisk został użyty do zamknięcia okna, oto składnia konstruktora i funkcji (parametr pos określa gdzie dialog ma się pojawić, MSWindows nie wykorzystuje tego parametru):

wx.MessageDialog(parent, message, caption = "Message box", style = wx.OK | wx.CANCEL, pos = wx.DefaultPosition)
wx.MessageBox(message, caption="Message", style=wx.OK)

Klasa wx.TextEntryDialog może przyjmować style znane z wx.TextCtrl (wx.TE_PASSWORD, wx.TE_MULTILINE, wx.TE_LEFT, wx.TE_RIGHT i wx.TE_CENTER), a także style opisujące przyciski (wx.ID_OK, wx.ID_CANCEL), funkcja wx.GetNumberFromUser przyjmuje jeden napis więcej - parametr zwany prompt występuje bezpośrednio przed liczbą, a także trzy parametry liczbowe - minimalna, maksymalna i początkowa wartość, gdy użytkownik zamknie dialog przy pomocy przycisku cancel zwracana jest wartość -1, jeśli poda liczbę większą od maksimum lub mniejszą od minimum to zwracane jest odpowiednio maksimum lub minimum. Pobieranie tekstu czy hasła zwraca pusty napis, gdy użytkownik zamknie dialog przyciskiem cancel, oto składnia:

wx.TextEntryDialog(parent, message, caption = "Please enter text", defaultValue = "", style = wx.OK | wx.CANCEL | wx.CENTRE, pos = wx.DefaultPosition)
wx.GetTextFromUser(message, caption = "Input text", default_value = "", parent = None)
wx.GetPasswordFromUser(message, caption = "Input text", default_value = "", parent = None)
wx.GetNumberFromUser(message, prompt, caption, value, min = 0, max = 100, parent = None)

Klasa wx.SingleChoiceDialog udostępnia metody GetSelection(), SetSelection(string) i GetSelectionIndex(), funkcja wx.GetSingleChoiceIndex zwraca -1 gdy wciśnięto klawisz cancel, oto składnia:

wx.SingleChoiceDialog(parent, message, caption, choices, clientData = None, style = wx.OK | wx.CANCEL | wx.CENTRE, pos = wx.DefaultPosition)
wx.GetSingleChoice(message, caption, aChoices, parent = None)
wx.GetSingleChoiceIndex(message, caption, aChoices, parent = None)

Klasa wx.FileDialog ma dwa podstawowe style wx.OPEN i wx.SAVE, przy ustawieniu wx.OPEN, można ustawić wx.MULTIPLE pozwalający zaznaczyć wiele plików i wx.HIDE_READONLY - wyłączający opcję czytania tylko do odczytu, przy wx.SAVE możliwe jest wx.OVERWRITE_PROMPT, który zapewni sprawdzanie, upewnianie się czy użytkownik na pewno chce napisać dany plik, zawsze można ustawić wx.CHANGE_DIR, powodujący zmianę bieżącego katalogu na ten z którego pobrano plik. Klasa udostępnia metody do odczytu wybranej przez użytkownika ścieżki: GetPaht(), GetPaths() (przy wx.MULTIPLE zwraca listę), a także metody dostępu do filtrów (wildcardów) SetFilterIndex(), GetFilterIndex(). Przy zapisywaniu jeśli użytkownik sam nie poda rozszerzenia to dodawane jest default_extension, sposób tworzenia wildcardów proszę zrozumieć na podstawie przykładu. Funkcja zwraca ścieżkę w postaci napisu, albo gdy zamknięto dialog przy pomocy cancel. Oto składnia:

wx.FileDialog(parent, message = "Choose a file", defaultDir = "", defaultFile = "", wildcard = "*.*", style = 0, pos = wx.DefaultPosition)
wx.FileSelector(message, default_path = "", default_filename = "", default_extension = "", wildcard = "*.*", flags = 0, parent = None, x = -1, y = -1)

Klasa wx.DirDialog ma jedną opcjonalną flagę: wx.DD_NEW_DIR_BUTTON powodującą umożliwienie utworzenia nowego katalogu, funkcja zwraca to co w przypadku wx.FileSelector, oto składnia:

wx.DirDialog(parent, message = "Choose a directory", defaultPath = "", style = 0, pos = wx.DefaultPosition, size = wx.DefaultSize, name = "wxDirCtrl")
wx.DirSelector(message = wx.DirSelectorPromptStr, default_path = "", style = 0, pos = wxDefaultPosition, parent = None)

"Programowanie dla Fizyków Medycznych"