18. Dialoger

Dialogfönster liknar väldigt mycket standardfönster, och används för att tillhandahålla eller erhålla information från användaren. De används ofta för att exempelvis tillhandahålla ett inställningsfönster. Den stora skillnaden som en dialog har är några i förväg packade komponenter som automatiskt gör en layout för dialogen. Därifrån kan vi enkelt lägga till etiketter, knappar, kryssrutor o.s.v. En annan stor skillnad är hanteringen av svar för att styra hur programmet ska bete sig efter interaktion med dialogen.

Det finns flera härledda Dialog-klasser som du kan finna användbara. Gtk.MessageDialog används för de flesta enkla aviseringar. Men vid andra tillfällen kan du behöva härleda din egen dialogklass för att tillhandahålla mer komplex funktionalitet.

18.1. Anpassade dialoger

För att packa komponenter i en anpassad dialog bör du packa dem i din Gtk.Box, tillgänglig via Gtk.Dialog.get_content_area(). För att bara lägga till en Gtk.Button längst ner i dialogen kan du använda metoden Gtk.Dialog.add_button().

En ”modal” dialog (det vill säga en som fryser resten av programmet från användarinmatning) kan skapas genom att anropa Gtk.Dialog.set_modal på dialogen eller ställa in argumentet flags för konstruktorn Gtk.Dialog att inkludera flaggan Gtk.DialogFlags.MODAL.

Att klicka på en knapp kommer sända ut en signal kallad ”response”. Om du vill blockera och vänta på att en dialog ska returnera innan du returnerar kontrollflödet till din kod kan du anropa Gtk.Dialog.run(). Denna metod returnerar en int som kan vara ett värde från Gtk.ResponseType eller så kan den vara det anpassade svarsvärdet som du angav i Gtk.Dialog-konstruktorn eller Gtk.Dialog.add_button().

Slutligen finns det två sätt att ta bort en dialog. Metoden Gtk.Widget.hide() får dialogen att sluta visas, men behåller den i minnet. Detta är användbart för att slippa behöva konstruera dialogen igen om den behöver kommas åt vid ett senare tillfälle. Alternativt kan metoden Gtk.Widget.destroy() användas för att ta bort dialogen från minnet då den inte längre behövs. Det bör noteras att om dialogen behöver kommas åt efter att den förstörts så kommer den behöva konstrueras igen, annars kommer dialogfönstret vara tomt.

18.1.1. Exempel

_images/dialog_example.png
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk


class DialogExample(Gtk.Dialog):
    def __init__(self, parent):
        super().__init__(title="My Dialog", transient_for=parent, flags=0)
        self.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK
        )

        self.set_default_size(150, 100)

        label = Gtk.Label(label="This is a dialog to display additional information")

        box = self.get_content_area()
        box.add(label)
        self.show_all()


class DialogWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="Dialog Example")

        self.set_border_width(6)

        button = Gtk.Button(label="Open dialog")
        button.connect("clicked", self.on_button_clicked)

        self.add(button)

    def on_button_clicked(self, widget):
        dialog = DialogExample(self)
        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            print("The OK button was clicked")
        elif response == Gtk.ResponseType.CANCEL:
            print("The Cancel button was clicked")

        dialog.destroy()


win = DialogWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

18.2. MessageDialog

Gtk.MessageDialog är en bekvämlighetsklass, använd för att skapa enkla standardmeddelandedialoger, med ett meddelande, en ikon och knappar för användarsvar. Du kan ange meddelandetypen och texten i Gtk.MessageDialog-konstruktorn, såväl som att ange standardknappar.

I några dialoger som kräver vidare förklaring av vad som har hänt kan en sekundär text läggas till. I detta fall görs det primära meddelandet som matats in då meddelandedialogen skapades större och ställs in till fetstil. Det sekundära meddelandet kan ställas in genom att anropa Gtk.MessageDialog.format_secondary_text().

18.2.1. Exempel

_images/messagedialog_example.png
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk


class MessageDialogWindow(Gtk.Window):
    def __init__(self):
        super().__init__(title="MessageDialog Example")

        box = Gtk.Box(spacing=6)
        self.add(box)

        button1 = Gtk.Button(label="Information")
        button1.connect("clicked", self.on_info_clicked)
        box.add(button1)

        button2 = Gtk.Button(label="Error")
        button2.connect("clicked", self.on_error_clicked)
        box.add(button2)

        button3 = Gtk.Button(label="Warning")
        button3.connect("clicked", self.on_warn_clicked)
        box.add(button3)

        button4 = Gtk.Button(label="Question")
        button4.connect("clicked", self.on_question_clicked)
        box.add(button4)

    def on_info_clicked(self, widget):
        dialog = Gtk.MessageDialog(
            transient_for=self,
            flags=0,
            message_type=Gtk.MessageType.INFO,
            buttons=Gtk.ButtonsType.OK,
            text="This is an INFO MessageDialog",
        )
        dialog.format_secondary_text(
            "And this is the secondary text that explains things."
        )
        dialog.run()
        print("INFO dialog closed")

        dialog.destroy()

    def on_error_clicked(self, widget):
        dialog = Gtk.MessageDialog(
            transient_for=self,
            flags=0,
            message_type=Gtk.MessageType.ERROR,
            buttons=Gtk.ButtonsType.CANCEL,
            text="This is an ERROR MessageDialog",
        )
        dialog.format_secondary_text(
            "And this is the secondary text that explains things."
        )
        dialog.run()
        print("ERROR dialog closed")

        dialog.destroy()

    def on_warn_clicked(self, widget):
        dialog = Gtk.MessageDialog(
            transient_for=self,
            flags=0,
            message_type=Gtk.MessageType.WARNING,
            buttons=Gtk.ButtonsType.OK_CANCEL,
            text="This is an WARNING MessageDialog",
        )
        dialog.format_secondary_text(
            "And this is the secondary text that explains things."
        )
        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            print("WARN dialog closed by clicking OK button")
        elif response == Gtk.ResponseType.CANCEL:
            print("WARN dialog closed by clicking CANCEL button")

        dialog.destroy()

    def on_question_clicked(self, widget):
        dialog = Gtk.MessageDialog(
            transient_for=self,
            flags=0,
            message_type=Gtk.MessageType.QUESTION,
            buttons=Gtk.ButtonsType.YES_NO,
            text="This is an QUESTION MessageDialog",
        )
        dialog.format_secondary_text(
            "And this is the secondary text that explains things."
        )
        response = dialog.run()
        if response == Gtk.ResponseType.YES:
            print("QUESTION dialog closed by clicking YES button")
        elif response == Gtk.ResponseType.NO:
            print("QUESTION dialog closed by clicking NO button")

        dialog.destroy()


win = MessageDialogWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

18.3. FileChooserDialog

Gtk.FileChooserDialog är lämplig för användning med menyobjekten ”Arkiv/Öppna” eller ”Arkiv/Spara”. Du kan använda alla metoder för Gtk.FileChooser på filväljardialogen såväl som de för Gtk.Dialog.

När du skapar en Gtk.FileChooserDialog måste du definiera dialogens syfte:

Gtk.FileChooserDialog ärver från Gtk.Dialog, så knappar har svars-ID:n så som Gtk.ResponseType.ACCEPT och Gtk.ResponseType.CANCEL vilka kan anges i konstruktorn för Gtk.FileChooserDialog. I kontrast till Gtk.Dialog så kan du inte använda anpassade svarskoder med Gtk.FileChooserDialog. Den förväntar sig att åtminstone en knapp kommer ha följande svars-ID:n:

När användaren är klar med att välja filer kan ditt program få de valda namnen antingen som filnamn (Gtk.FileChooser.get_filename()) eller som URI:er (Gtk.FileChooser.get_uri()).

Som standard tillåter Gtk.FileChooser endast att en fil väljs åt gången. För att aktivera val av flera filer, använd Gtk.FileChooser.set_select_multiple(). Att erhålla en lista över valda filer är möjligt med antingen Gtk.FileChooser.get_filenames() eller Gtk.FileChooser.get_uris().

Gtk.FileChooser stöder också ett antal alternativ som gör filerna och mapparna mer konfigurerbara och åtkomliga.

Vidare kan du ange vilka typer av filer som visas genom att skapa Gtk.FileFilter-objekt och anropa Gtk.FileChooser.add_filter(). Användaren kan sedan välja ett av de tillagda filtren från en kombinationsruta längst ner i filväljaren.

18.3.1. Exempel

_images/filechooserdialog_example.png
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk


class FileChooserWindow(Gtk.Window):
    def __init__(self):
        super().__init__(title="FileChooser Example")

        box = Gtk.Box(spacing=6)
        self.add(box)

        button1 = Gtk.Button(label="Choose File")
        button1.connect("clicked", self.on_file_clicked)
        box.add(button1)

        button2 = Gtk.Button(label="Choose Folder")
        button2.connect("clicked", self.on_folder_clicked)
        box.add(button2)

    def on_file_clicked(self, widget):
        dialog = Gtk.FileChooserDialog(
            title="Please choose a file", parent=self, action=Gtk.FileChooserAction.OPEN
        )
        dialog.add_buttons(
            Gtk.STOCK_CANCEL,
            Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN,
            Gtk.ResponseType.OK,
        )

        self.add_filters(dialog)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            print("Open clicked")
            print("File selected: " + dialog.get_filename())
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        dialog.destroy()

    def add_filters(self, dialog):
        filter_text = Gtk.FileFilter()
        filter_text.set_name("Text files")
        filter_text.add_mime_type("text/plain")
        dialog.add_filter(filter_text)

        filter_py = Gtk.FileFilter()
        filter_py.set_name("Python files")
        filter_py.add_mime_type("text/x-python")
        dialog.add_filter(filter_py)

        filter_any = Gtk.FileFilter()
        filter_any.set_name("Any files")
        filter_any.add_pattern("*")
        dialog.add_filter(filter_any)

    def on_folder_clicked(self, widget):
        dialog = Gtk.FileChooserDialog(
            title="Please choose a folder",
            parent=self,
            action=Gtk.FileChooserAction.SELECT_FOLDER,
        )
        dialog.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, "Select", Gtk.ResponseType.OK
        )
        dialog.set_default_size(800, 400)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            print("Select clicked")
            print("Folder selected: " + dialog.get_filename())
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        dialog.destroy()


win = FileChooserWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()