Optimierungspotential für GUI - mit Minimalbeispiel

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Sören
User
Beiträge: 5
Registriert: Montag 18. Januar 2016, 12:11

Hallo zusammen,
ich beschäftige mich derzeit mit Python im Allgemeinen und wx.Python als GUI-Framework. Bis jetzt konnte ich relativ viele Fragen durch googeln selbst klären, doch nun stoße ich langsam an meine Grenzen und hoffe auf ein paar hilfreiche Hinweise von erfahrenen Nutzern.

Zum besseren Verständnis habe ich ein „Minimalbeispiel“, einen Screenshot und ein Klassendiagramm angefügt. (Leider darf ich als neuer Nutzer offensichtlich keine Dateien anhängen, so dass ich erstmal nur das Minimalbeispiel unten angehängt habe.)

Die Anwendung soll einen Startup-Bildschirm haben und nach Aufforderung durch den User (z.Z Klick auf Datei=>Neu) in den „Produktivmodus“ umschalten. Der Screenshot zeigt, wie ich mir diese Ansicht im Wesentlichen vorstelle. Leider gibt es noch ein paar Punkte, die mir nicht so gut gefallen und für die ich bis jetzt noch keine Lösung gefunden habe.
  1. Durch die Verschachtelung der verschiedenen Elemente scheinen bestimmte Elemente (Splitter, Notebook, …) eigene Rahmen zu zeichnen. Da ich Default-Einstellungen verwende ist dies sicher seitens des GUI-Frameworks korrekt. Wie verhindere ich diese Rahmendarstellung, so dass sich z.B. die beiden geschachtelten Splitter für den Nutzer wie ein MultiSplitterWindow darstellen? (wx.NO_BORDER etc. habe ich erfolglos probiert, so dass ich einen Denkfehler meinerseits vermute.)
    Anm. 1: Ich verwende bewusst kein MultiSplitterWindow, da dieses keine Gravity zur Verfügung stellt.
    Anm. 2: Den Style NB_MULTILINE kann ich nicht verwenden, da die Anwendung auf Windows und Linux laufen soll.
  2. Zum Thema MultiSplitterWindow, habe ich unabhängig vom Minimalbeispiel eine Frage: Ist es möglich diesem mitzugeben, dass es bei Größenänderungen die einzelnen Elemente proportional zur Ausgangsgröße skaliert? (Ich habe es nur geschafft, dass alle Elemente die gleiche Größe beibehalten haben und das rechteste bzw. unterste Element skaliert wurde.)
  3. Auf der obersten Strukturebene habe ich das Fenster in zwei Bereiche untergliedert. Der linke Bereich enthält zwei Überblicksspalten mit entsprechender Überschrift. Verkleinert man einen oder beide Überblicksbereiche derart, dass die jeweiligen Überschriften nicht mehr vollständig dargestellt werden können, verschwinden diese – im Gegensatz zu den Einträgen – komplett. Was habe ich falsch gemacht, da ich eigentlich möchte, dass die Überschriften, wie die Einträge auch, einfach nur abgeschnitten werden sollen?
  4. Die Skalierung der Elemente scheint im Minimalbeispiel bis auf die CSheets zu funktionieren. Welchen Fehler habe ich gemacht, dass die CSheets im Notebook erst an den zur Verfügung stehenden Platz angepasst werden, wenn der Sash des vertikalen Splitters bewegt wird?
  5. Bewegt man eben diesen Sash, krallen sich die CSheets den zur Verfügung stehenden Platz vollständig. Was müsste ich ergänzen, um dafür zu sorgen, dass die CSheets nur den von ihnen benötigten Platz einnehmen und der Rest in der Hintergrundfarbe dargestellt wird?
Für Hinweise, auch auf die entscheidenden Abschnitte der Dokumentationen, würde ich mich freuen.

Vielen Danke.
Sören

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: latin-1 -*-
'''
Created on 14.01.2016

@author: Sören
'''

import wx
from wx.lib import sheet

'''
Hierarchie:
wx.Frame (Fenster)
    wx.Panel (Startbildschirm)
    wx.Panel (Hauptbildschirm)
        Multislpitter horizontal => Da für Multisplitter keine Gravityfunktion existiert, wurden geschachtelte SplitterWindows verwendet
        - Links(1/6 Bildschirmbreite): Konten mit Überschrift
        - Mitte(1/6 Bildschirmbreite): Kategorien mit Überschrift
        - Rechts (2/3 Bildschirmbreite: Doppeltes Notebook
            wx.notebook (Jahre)
                wx.notebook (Monate)
                    SplitterWindow vertikal
                    - Oben (1/2 Bildschirmhöhe): Transfer mit Überschrift
                    - Unten (1/2 Bildschirmhöhe): Buchungen mit Überschrift
        
'''

class Panel_Startup(wx.Panel):
    def __init__(self, parent, color):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        self.SetBackgroundColour(color)

class Panel_Entry(wx.Panel):
    def __init__(self, parent, name, value):
        wx.Panel.__init__(self, parent)
        
        text = wx.StaticText(self, -1, " " + str(name) + ":", size=(-1,16))
        text.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))
        
        value = wx.StaticText(self, -1, str(value), pos=(100,-1),size=(-1,16))
        value.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))
        
class Panel_Overview_Category(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        heading = wx.StaticText(self, -1, " Kategorien:", size=(-1,25))
        heading.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
        
        example1 = Panel_Entry(self, "Kategorie 1", 100)
        example2 = Panel_Entry(self, "Kategorie 2", 20)
        example3 = Panel_Entry(self, "Kategorie 3", 1)
        
        sizer.Add(heading, 0, wx.EXPAND)
        sizer.Add(example1, 0, wx.EXPAND)
        sizer.Add(example2, 0, wx.EXPAND)
        sizer.Add(example3, 0, wx.EXPAND)
        
        self.SetSizer(sizer)
        
class Panel_Overview_Account(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        heading = wx.StaticText(self, -1, " Konten:", size=(-1,25))
        heading.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
        
        example1 = Panel_Entry(self, "Konto A", 0)
        example2 = Panel_Entry(self, "Konto B", 50)
        example3 = Panel_Entry(self, "Konto C", 1000)
        
        sizer.Add(heading, 0, wx.EXPAND)
        sizer.Add(example1, 0, wx.EXPAND)
        sizer.Add(example2, 0, wx.EXPAND)
        sizer.Add(example3, 0, wx.EXPAND)
        
        self.SetSizer(sizer)

class Transfer_Sheet(sheet.CSheet):
    def __init__(self, parent):
        sheet.CSheet.__init__(self, parent)
        self.row = self.col = 0
        self.SetNumberRows(20)
        self.SetNumberCols(5)
        self.SetColLabelValue(0, "Datum")
        self.SetColLabelValue(1, "Betrag")
        self.SetColLabelValue(2, "Quelle")
        self.SetColLabelValue(3, "Ziel")
        self.SetColLabelValue(4, "Bemerkung")
        self.SetColSize(4,200)
        
class Booking_Sheet(sheet.CSheet):
    def __init__(self, parent):
        sheet.CSheet.__init__(self, parent)
        self.row = self.col = 0
        self.SetNumberRows(20)
        self.SetNumberCols(5)
        self.SetColLabelValue(0, "Datum")
        self.SetColLabelValue(1, "Betrag")
        self.SetColLabelValue(2, "Kategorie")
        self.SetColLabelValue(3, "Konto")
        self.SetColLabelValue(4, "Bemerkung")
        self.SetColSize(4,200)
        
class Panel_Box_Transfer(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        heading = wx.StaticText(self, -1, " Transfers", size=(-1,25))
        heading.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))

        table = Transfer_Sheet(self)
        
        sizer.Add(heading, 0, wx.EXPAND)
        sizer.Add(table, 1, wx.EXPAND)
        
        self.SetSizer(sizer)

class Panel_Box_Booking(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        heading = wx.StaticText(self, -1, " Buchungen", size=(-1,25))
        heading.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))

        table = Booking_Sheet(self)
        
        sizer.Add(heading, 0, wx.EXPAND)
        sizer.Add(table, 1, wx.EXPAND)
        
        self.SetSizer(sizer)

class Panel_Splitter_Entry(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        
        splitter = wx.SplitterWindow(self)
        splitter.SetMinimumPaneSize(wx.DisplaySize()[1]/8)
        
        panel_transfer = Panel_Box_Transfer(splitter)
        panel_booking = Panel_Box_Booking(splitter)
        
        splitter.SplitHorizontally(panel_transfer, panel_booking)
        splitter.SetSashGravity(0.5)
        
        sizer.Add(splitter, 1, wx.EXPAND)
        self.SetSizer(sizer)
        
class Panel_Notebook_Month(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        sizer = wx.BoxSizer(wx.VERTICAL)
                
        notebook = wx.Notebook(self, -1)
        
        sheet_jan = Panel_Splitter_Entry(notebook)
        sheet_feb = Panel_Splitter_Entry(notebook)
        sheet_mrz = Panel_Splitter_Entry(notebook)
        sheet_apr = Panel_Splitter_Entry(notebook)
        sheet_mai = Panel_Splitter_Entry(notebook)
        sheet_jun = Panel_Splitter_Entry(notebook)
        sheet_jul = Panel_Splitter_Entry(notebook)
        sheet_aug = Panel_Splitter_Entry(notebook)
        sheet_sep = Panel_Splitter_Entry(notebook)
        sheet_okt = Panel_Splitter_Entry(notebook)
        sheet_nov = Panel_Splitter_Entry(notebook)
        sheet_dez = Panel_Splitter_Entry(notebook)
        sheet_jan.SetFocus()

        notebook.AddPage(sheet_jan, 'Jan.')
        notebook.AddPage(sheet_feb, 'Feb.')
        notebook.AddPage(sheet_mrz, 'März')
        notebook.AddPage(sheet_apr, 'April')
        notebook.AddPage(sheet_mai, 'Mai')
        notebook.AddPage(sheet_jun, 'Juni')
        notebook.AddPage(sheet_jul, 'Juli')
        notebook.AddPage(sheet_aug, 'Aug.')
        notebook.AddPage(sheet_sep, 'Sept.')
        notebook.AddPage(sheet_okt, 'Okt.')
        notebook.AddPage(sheet_nov, 'Nov.')
        notebook.AddPage(sheet_dez, 'Dez.')
        
        sizer.Add(notebook, 1, wx.EXPAND)
        
        self.SetSizer(sizer)

class Panel_Notebook(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        sizer = wx.BoxSizer(wx.VERTICAL)
                
        notebook = wx.Notebook(self, -1)
        
        sheet1 = Panel_Notebook_Month(notebook)
        sheet2 = Panel_Notebook_Month(notebook)
        sheet3 = Panel_Notebook_Month(notebook)
        sheet1.SetFocus()

        notebook.AddPage(sheet1, '2014')
        notebook.AddPage(sheet2, '2015')
        notebook.AddPage(sheet3, '2016')
        
        sizer.Add(notebook, 1, wx.EXPAND)
        
        self.SetSizer(sizer)
       
class Panel_Main(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        main_splitter = wx.SplitterWindow(self)
        main_splitter.SetMinimumPaneSize(wx.DisplaySize()[0]/24)
        
        overview_splitter = wx.SplitterWindow(main_splitter)
        overview_splitter.SetMinimumPaneSize(wx.DisplaySize()[0]/48)
        
        panel_accounts = Panel_Overview_Account(overview_splitter)
        panel_categories = Panel_Overview_Category(overview_splitter)
        panel_notebook = Panel_Notebook(main_splitter)
        
        overview_splitter.SplitVertically(panel_accounts, panel_categories)
        overview_splitter.SetSashGravity(0.5)
        
        main_splitter.SplitVertically(overview_splitter, panel_notebook, -(2*parent.GetSize()[0]/3)) # Dritter Parameter funktioniert bei positiven Werten nicht sauber.
        main_splitter.SetSashGravity(0.5)
        
        sizer.Add(main_splitter, 1, wx.EXPAND)
        self.SetSizer(sizer)
        
class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, -1, title, size = (wx.DisplaySize()[0]/2, wx.DisplaySize()[1]/2), pos = (0,0))
        
        # Menü- und Statusbar
        menubar = wx.MenuBar()
        menu_file = wx.Menu() # Für Datei
        newfilemenu = menu_file.Append(wx.ID_NEW, "Neu"," Anlegen einer neuen Abrechnung")
        self.Bind(wx.EVT_MENU, self.Click_New, newfilemenu)
        menubar.Append(menu_file, "Datei") # Adding the "menu_file" to the MenuBar
        self.SetMenuBar(menubar)
        self.CreateStatusBar()

        # Bildschirme
        self.panel_startup = Panel_Startup(self, 'red')
        self.panel_main = Panel_Main(self)
        self.panel_main.Hide()
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.panel_startup, 1, wx.EXPAND)
        sizer.Add(self.panel_main, 1, wx.EXPAND)
        self.SetSizer(sizer)
        
        self.SetMinSize((640, 320))

    def Click_New(self, event):
        self.panel_startup.Hide()
        self.panel_main.Show()
        self.Layout()
        event.Skip()
        
app = wx.App()
myframe = MyFrame(None,-1,"GUI-Design Testwindow")
myframe.Show(True)
app.MainLoop()
Zuletzt geändert von Anonymous am Montag 18. Januar 2016, 15:08, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Sören: Ad 1. Ich denke nicht dass Du das verhindern kannst. In dem Theme welches ich unter Linux verwende haben die Splitter beispielsweise keinen Rahmen, ich würde mir allerdings einen wünschen, denn die sind deswegen schlechter zu erkennen. Im Gtk-Klassiker „Raleigh“ sind sie fast gar nicht zu erkennen. Beim „Redmond“-Theme, mit deutlicher Licht und Schattenseite, kann man den Splitter sehr gut wahrnehmen. Wx setzt auf ”native” GUI-Elemente, deswegen ist es relativ aussichtslos zu versuchen ”micro managing” beim Aussehen zu betreiben. Das kann auf jedem System anders aussehen und ist auf *einem* System dann auch noch vom eingestellten Theme abhängig.

Ad 2. Das scheint nicht möglich zu sein.

Ad 3. Nimm mal das `wx.EXPAND` beim Hinzufügen zum Sizer heraus.

Ad 4. und 5. Das kann ich unter Linux nicht nachvollziehen.

Anmerkungen zum Quelltext:

Zeichenketten sind kein Mittel für Kommentare. Dafür gibt es das ``#``-Zeichen. Spezielle Blockkommentare gibt es syntaktisch nicht.

Unterstriche in Klassennamen kommen weder bei Python noch bei wxWidgets (C++) vor. Der Präfix `Panel` wäre eher ein Suffix. Das entspricht mehr der natürlichen Sprache.

Ein Docstring für eine `__init__()` der einfach nur aus dem Wort 'Constructor' besteht, bringt keinerlei Mehrwert. Im Grunde ist es sogar falsch, weil der Konstruktor in Python `__new__()` heisst. `__init__()` initialisiert ein bereits bestehendes Objekt.

Zusammensetzen von Zeichenketten und Werten per `str()` und ``+`` ist eher BASIC als Python. Es gibt die `format()`-Methode auf Zeichenketten dafür.

Für die -1 als ID gibt es die Konstante `wx.ID_ANY`. Dann kann man gleich sehen wo eine -1 eine ID meint die von wx vergeben wird und wo sie etwas anderes bedeutet.

Die beiden Übersichtspanels haben fast gleichen Quelltext, das könnte man leicht zusammenfassen. Das gleiche gilt für die beiden `CSheet`-Unterklassen. Und auch für die beiden Klassen in die das dann gekapselt wird.

Bei einigen Klassen steck im Namen in welchem Containerwidgettyp die später mal angezeigt weden ohne das das zwingend erforderlich wäre.

Auf Modulebene sollten nur Konstanten, Funktionen, und Klassen definiert werden. Das Hauptprogramm steht üblicherweise in einer `main()`-Funktion.

Zwischenergebnis:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: latin-1 -*-
"""
Created on 14.01.2016
 
@author: Sören
"""
import wx
from wx.lib import sheet

# Hierarchie:
# wx.Frame (Fenster)
#    wx.Panel (Startbildschirm)
#    wx.Panel (Hauptbildschirm)
#        Multislpitter horizontal => Da für Multisplitter keine Gravityfunktion
#        existiert, wurden geschachtelte SplitterWindows verwendet
#        - Links(1/6 Bildschirmbreite): Konten mit Überschrift
#        - Mitte(1/6 Bildschirmbreite): Kategorien mit Überschrift
#        - Rechts (2/3 Bildschirmbreite: Doppeltes Notebook
#            wx.notebook (Jahre)
#                wx.notebook (Monate)
#                    SplitterWindow vertikal
#                    - Oben (1/2 Bildschirmhöhe): Transfer mit Überschrift
#                    - Unten (1/2 Bildschirmhöhe): Buchungen mit Überschrift

class StartupPanel(wx.Panel):

    def __init__(self, parent, color):
        wx.Panel.__init__(self, parent)
        self.SetBackgroundColour(color)


class EntryPanel(wx.Panel):

    def __init__(self, parent, name, value):
        wx.Panel.__init__(self, parent)

        text = wx.StaticText(
            self, wx.ID_ANY, ' {0}:'.format(name), size=(-1, 16)
        )
        text.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))

        value = wx.StaticText(
            self, wx.ID_ANY, str(value), pos=(100, -1), size=(-1, 16)
        )
        value.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))


class CategoryOverviewPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        sizer = wx.BoxSizer(wx.VERTICAL)

        heading = wx.StaticText(self, -1, ' Kategorien:', size=(-1, 25))
        heading.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
        sizer.Add(heading, 0)

        for name, value in [
            ('Kategorie 1', 100), ('Kategorie 2', 20), ('Kategorie 3', 1)
        ]:
            sizer.Add(EntryPanel(self, name, value), 0, wx.EXPAND)

        self.SetSizer(sizer)


class AccountOverviewPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        sizer = wx.BoxSizer(wx.VERTICAL)

        heading = wx.StaticText(self, -1, ' Konten:', size=(-1, 25))
        heading.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
        sizer.Add(heading, 0)

        for name, value in [('Konto A', 0), ('Konto B', 50), ('Konto C', 1000)]:
            sizer.Add(EntryPanel(self, name, value), 0, wx.EXPAND)

        self.SetSizer(sizer)


class TransferSheet(sheet.CSheet):

    def __init__(self, parent):
        sheet.CSheet.__init__(self, parent)
        self.row = self.col = 0
        self.SetNumberRows(20)
        label_names = ['Datum', 'Betrag', 'Quelle', 'Ziel', 'Bemerkung']
        self.SetNumberCols(len(label_names))
        for i, name in enumerate(label_names):
            self.SetColLabelValue(i, name)
        self.SetColSize(4, 200)


class BookingSheet(sheet.CSheet):

    def __init__(self, parent):
        sheet.CSheet.__init__(self, parent)
        self.row = self.col = 0
        self.SetNumberRows(20)
        label_names = ['Datum', 'Betrag', 'Kategorie', 'Konto', 'Bemerkung']
        self.SetNumberCols(len(label_names))
        for i, name in enumerate(label_names):
            self.SetColLabelValue(i, name)
        self.SetColSize(4, 200)


class TransferBoxPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        sizer = wx.BoxSizer(wx.VERTICAL)

        heading = wx.StaticText(self, -1, ' Transfers', size=(-1, 25))
        heading.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))

        table = TransferSheet(self)

        sizer.Add(heading, 0)
        sizer.Add(table, 1, wx.EXPAND)

        self.SetSizer(sizer)


class BookingBoxPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        sizer = wx.BoxSizer(wx.VERTICAL)

        heading = wx.StaticText(self, -1, ' Buchungen', size=(-1, 25))
        heading.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))

        table = BookingSheet(self)

        sizer.Add(heading, 0)
        sizer.Add(table, 1, wx.EXPAND)

        self.SetSizer(sizer)


class SplitterEntryPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        sizer = wx.BoxSizer(wx.HORIZONTAL)

        splitter = wx.SplitterWindow(self)
        splitter.SetMinimumPaneSize(wx.DisplaySize()[1] / 8)

        splitter.SplitHorizontally(
            TransferBoxPanel(splitter), BookingBoxPanel(splitter)
        )
        splitter.SetSashGravity(0.5)

        sizer.Add(splitter, 1, wx.EXPAND)
        self.SetSizer(sizer)


class MonthNotebookPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        sizer = wx.BoxSizer(wx.VERTICAL)

        notebook = wx.Notebook(self)
        month_names = [
            'Jan.', 'Feb.', 'März', 'April', 'Mai', 'Juni',
            'Juli', 'Aug.', 'Sept.', 'Okt.', 'Nov.', 'Dez.'
        ]
        for name in month_names:
            notebook.AddPage(SplitterEntryPanel(notebook), name)

        sizer.Add(notebook, 1, wx.EXPAND)
        self.SetSizer(sizer)


class NotebookPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        sizer = wx.BoxSizer(wx.VERTICAL)

        notebook = wx.Notebook(self)
        for year in [2014, 2015, 2016]:
            notebook.AddPage(MonthNotebookPanel(notebook), str(year))

        sizer.Add(notebook, 1, wx.EXPAND)
        self.SetSizer(sizer)


class MainPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        sizer = wx.BoxSizer(wx.VERTICAL)

        main_splitter = wx.SplitterWindow(self)
        main_splitter.SetMinimumPaneSize(wx.DisplaySize()[0] / 24)

        overview_splitter = wx.SplitterWindow(main_splitter)
        overview_splitter.SetMinimumPaneSize(wx.DisplaySize()[0] / 48)

        accounts_panel = AccountOverviewPanel(overview_splitter)
        categories_panel = CategoryOverviewPanel(overview_splitter)
        notebook_panel = NotebookPanel(main_splitter)

        overview_splitter.SplitVertically(accounts_panel, categories_panel)
        overview_splitter.SetSashGravity(0.5)

        # Dritter Parameter funktioniert bei positiven Werten nicht sauber.
        main_splitter.SplitVertically(
            overview_splitter, notebook_panel, -(2 * parent.GetSize()[0] / 3)
        )
        main_splitter.SetSashGravity(0.5)

        sizer.Add(main_splitter, 1, wx.EXPAND)
        self.SetSizer(sizer)


class MainFrame(wx.Frame):

    def __init__(self, parent, id, title):
        width, height = wx.DisplaySize()
        wx.Frame.__init__(
            self,
            parent,
            wx.ID_ANY,
            title,
            size=(width / 2, height / 2),
            pos=(0, 0)
        )
        menubar = wx.MenuBar()
        file_menu = wx.Menu()
        newfilemenu = file_menu.Append(
            wx.ID_NEW, '&Neu', 'Anlegen einer neuen Abrechnung'
        )
        self.Bind(wx.EVT_MENU, self.on_new, newfilemenu)
        menubar.Append(file_menu, '&Datei')
        self.SetMenuBar(menubar)
        self.CreateStatusBar()

        self.startup_panel = StartupPanel(self, 'red')
        self.main_panel = MainPanel(self)
        self.main_panel.Hide()
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.startup_panel, 1, wx.EXPAND)
        sizer.Add(self.main_panel, 1, wx.EXPAND)
        self.SetSizer(sizer)

        self.SetMinSize((640, 320))

    def on_new(self, event):
        self.startup_panel.Hide()
        self.main_panel.Show()
        self.Layout()
        event.Skip()


def main():
    app = wx.App()
    window = MainFrame(None, wx.ID_ANY, 'GUI-Design Testwindow')
    window.Show(True)
    app.MainLoop()


if __name__ == '__main__':
    main()
Sören
User
Beiträge: 5
Registriert: Montag 18. Januar 2016, 12:11

@ BlackJack: Wow. Vielen Dank für die Mühe…

Zu 1: Wenn ich dich richtig verstanden habe, ist die Kernaussage, dass wx.Python für detailverliebte Programmierer eher nicht die richtige Wahl ist, da die Einstellmöglichkeiten für die Details begrenzt sind. Gibt es ein anderes Framework, mit dem die Einstellungen solcher Details eher realisierbar sind? Alternativ könnte ich mir auch vorstellen, die einzelnen Elemente in vom Nutzer frei platzierbare „Unterfenster“ (Wie nennt man die?) auszulagern, damit dürften keine geschachtelten Rahmen mehr dargestellt werden, die man nicht gewohnt wäre.

Zu 2: Habe ich befürchtet.

Zu 3: Hat unter Windows keine Auswirkung => Verschwindet immer noch. Unter Linux habe ich es noch nicht versucht, werde ich aber aufgrund 4 und 5 einmal probieren…

Bzgl. Anmerkungen zum Quelltext: Danke, manches ist mir klar (und wurde aufgrund Minimalbeispiel ignoriert), anderes ist mir jetzt klarer.
BlackJack

@Sören: Ich denke kein gängiges GUI-Rahmenwerk ist für ”detailverliebte” Programmierer, selbst wenn es solche Einstellungen ermöglicht. GUI-Rahmenwerke benutzt man ja gerade damit man sich nicht um solche Details kümmern muss, sondern auf höherer Ebene Anzeigeelemente zusammenstellen kann, so dass die GUI so aussieht wie der Benutzer das gewohnt ist, also die Darstellung dem System oder Theme folgt, welches er verwendet oder eingestellt hat.

Rahmen um Notebooks sind letztendlich nicht nur eine Geschmacksfrage, denn die Standardthemes orientieren sich heute nicht mehr nur an ”Schönheit” sondern auch an Benutzbarkeitsstudien. Wenn da Rahmen um Notebooks gezeichnet werden, würde ich erst einmal davon ausgehen, dass sich in Tests erwiesen hat, dass man die Tabs ohne Rahmen schlechter erkennen, also den Reiter dem Inhalt zuordnen kann. Der Rahmen hat eine Funktion. Dann sollte man sich gut überlegen ob man da mit dem persönlichen Geschmack ankommen möchte und eine GUI so ändert das sie nicht mehr so aussieht wie in allen anderen Fenstern die der Benutzer so kennt. Wer die Rahmen um Notebooks nicht mag wird das systemweit per Theme ändern. Da haben einzelne Anwendungsentwickler nichts mit zu tun.
Antworten