From 4f55701e1b291a9a6da9eb7aef5802e6bc20cbf0 Mon Sep 17 00:00:00 2001 From: emkael Date: Sun, 7 Jul 2019 20:45:05 +0200 Subject: Numeric values and spinboxes handled in custom widget --- jfr_playoff/gui/frames/__init__.py | 33 +++++++++----- jfr_playoff/gui/frames/match.py | 75 +++++++++++++++---------------- jfr_playoff/gui/frames/network.py | 29 ++++++------ jfr_playoff/gui/frames/team.py | 43 +++++++++--------- jfr_playoff/gui/frames/translations.py | 6 ++- jfr_playoff/gui/frames/visual.py | 81 ++++++++++++++++++---------------- jfr_playoff/gui/tabs.py | 15 ++++--- jfr_playoff/gui/variables.py | 24 ++++++++++ 8 files changed, 177 insertions(+), 129 deletions(-) create mode 100644 jfr_playoff/gui/variables.py diff --git a/jfr_playoff/gui/frames/__init__.py b/jfr_playoff/gui/frames/__init__.py index 89e0155..e50231d 100644 --- a/jfr_playoff/gui/frames/__init__.py +++ b/jfr_playoff/gui/frames/__init__.py @@ -7,11 +7,7 @@ import tkinter as tk from tkinter import ttk import tkMessageBox -def getIntVal(widget, default=0): - try: - return int(widget.get().strip()) - except ValueError: - return default +from ..variables import NotifyStringVar, NotifyIntVar, NotifyNumericVar def setPanelState(frame, state): for child in frame.winfo_children(): @@ -175,7 +171,7 @@ class RepeatableFrame(tk.Frame): class RepeatableEntry(RepeatableFrame): def renderContent(self): - self.value = tk.StringVar() + self.value = NotifyStringVar() self.field = ttk.Entry(self, textvariable=self.value) self.field.pack(expand=True, fill=tk.BOTH) @@ -262,7 +258,7 @@ class WidgetSelectionFrame(ScrollableFrame): addBtn.pack(side=tk.BOTTOM) def renderContent(self, container): - self.value = tk.IntVar() + self.value = NotifyIntVar() for idx, widget in enumerate(self.widgets): (ttk.Radiobutton( container, variable=self.value, value=idx, @@ -359,7 +355,7 @@ class SelectionFrame(ScrollableFrame): self.renderHeader(container) for idx, option in enumerate(self.options): key = self._mapValue(idx, option) - self.values[key] = tk.IntVar() + self.values[key] = NotifyIntVar() self.renderOption(container, option, idx) if self.selected and key in self.selected: self.values[key].set(True) @@ -369,7 +365,7 @@ class RefreshableOptionMenu(ttk.OptionMenu): self._valueVariable = variable self._valueVariable.trace('w', self._valueSet) self._lastValue = variable.get() - newVar = tk.StringVar() + newVar = NotifyStringVar() ttk.OptionMenu.__init__(self, master, newVar, *args, **kwargs) self._valueLock = False self.refreshOptions() @@ -457,4 +453,21 @@ class TraceableText(tk.Text): self._variableLock = False return result -# TODO: NumericSpinBox instead of getIntVal +class NumericSpinbox(tk.Spinbox): + def __init__(self, *args, **kwargs): + kwargs['justify'] = tk.RIGHT + self._variable = None + if 'textvariable' in kwargs: + self._variable = kwargs['textvariable'] + self._default = kwargs['from_'] if 'from_' in kwargs else 0 + tk.Spinbox.__init__(self, *args, **kwargs) + if self._variable is not None: + if not isinstance(self._variable, NotifyNumericVar): + raise AttributeError( + 'NumericSpinbox variable must be NotifyNumericVar') + self._variable.trace('w', self._onChange) + + def _onChange(self, *args): + val = self._variable.get() + if val is None: + self._variable.set(self._default) diff --git a/jfr_playoff/gui/frames/match.py b/jfr_playoff/gui/frames/match.py index 99eb1b3..4c8736c 100644 --- a/jfr_playoff/gui/frames/match.py +++ b/jfr_playoff/gui/frames/match.py @@ -5,23 +5,24 @@ from tkinter.font import Font from tkinter import ttk from ..frames import GuiFrame, RepeatableFrame, ScrollableFrame -from ..frames import WidgetRepeater, RepeatableEntry, getIntVal +from ..frames import WidgetRepeater, RepeatableEntry, NumericSpinbox from ..frames import SelectionFrame, SelectionButton, RefreshableOptionMenu from ..frames.team import DBSelectionField, TeamSelectionFrame from ..frames.team import TeamSelectionButton from ..frames.visual import PositionsSelectionFrame +from ..variables import NotifyStringVar, NotifyIntVar, NotifyNumericVar class SwissSettingsFrame(RepeatableFrame): SOURCE_LINK = 0 SOURCE_DB = 1 def _setPositionInfo(self, *args): - tournamentFrom = getIntVal(self.setFrom, default=1) + tournamentFrom = self.setFrom.get(default=1) tournamentTo = min( - getIntVal(self.setTo, default=1) \ + self.setTo.get(default=1) \ if self.setToEnabled.get() else 9999, len(self.winfo_toplevel().getTeams())) - swissFrom = getIntVal(self.fetchFrom, default=1) + swissFrom = self.fetchFrom.get(default=1) swissTo = swissFrom + tournamentTo - tournamentFrom if tournamentTo < tournamentFrom: self.positionsInfo.configure(text='brak miejsc do ustawienia') @@ -44,16 +45,16 @@ class SwissSettingsFrame(RepeatableFrame): else tk.DISABLED) def renderContent(self): - self.source = tk.IntVar() - self.fetchDB = tk.StringVar() - self.fetchLink = tk.StringVar() - self.setFrom = tk.StringVar() - self.setToEnabled = tk.IntVar() - self.setTo = tk.StringVar() - self.fetchFromEnabled = tk.IntVar() - self.fetchFrom = tk.StringVar() - self.linkLabel = tk.StringVar() - self.linkRelPath = tk.StringVar() + self.source = NotifyIntVar() + self.fetchDB = NotifyStringVar() + self.fetchLink = NotifyStringVar() + self.setFrom = NotifyNumericVar() + self.setToEnabled = NotifyIntVar() + self.setTo = NotifyNumericVar() + self.fetchFromEnabled = NotifyIntVar() + self.fetchFrom = NotifyNumericVar() + self.linkLabel = NotifyStringVar() + self.linkRelPath = NotifyStringVar() self.columnconfigure(1, weight=1) self.columnconfigure(2, weight=1) @@ -81,7 +82,7 @@ class SwissSettingsFrame(RepeatableFrame): (ttk.Label( self, text='Ustaw od miejsca: ')).grid( row=4, column=0, sticky=tk.W, padx=18) - (tk.Spinbox( + (NumericSpinbox( self, textvariable=self.setFrom, from_=1, to=999, width=5)).grid( row=4, column=1, sticky=tk.W) @@ -89,7 +90,7 @@ class SwissSettingsFrame(RepeatableFrame): self, variable=self.setToEnabled, text='Ustaw do miejsca: ')).grid( row=5, column=0, sticky=tk.W) - (tk.Spinbox( + (NumericSpinbox( self, textvariable=self.setTo, from_=1, to=999, width=5)).grid( row=5, column=1, sticky=tk.W) @@ -97,7 +98,7 @@ class SwissSettingsFrame(RepeatableFrame): self, variable=self.fetchFromEnabled, text='Pobierz od miejsca: ')).grid( row=6, column=0, sticky=tk.W) - (tk.Spinbox( + (NumericSpinbox( self, textvariable=self.fetchFrom, from_=1, to=999, width=5)).grid( row=6, column=1, sticky=tk.W) @@ -279,12 +280,12 @@ class BracketMatchSettingsFrame(GuiFrame): self.teams = [allTeams[idx-1] for idx in teams] def renderContent(self): - self.source = tk.IntVar() + self.source = NotifyIntVar() self.source.trace('w', self._enablePanels) self.source.trace('w', self._configChangeNotify) - self.selected = tk.IntVar() + self.selected = NotifyIntVar() self.selected.trace('w', self._enablePanels) - self.selectedIndex = tk.StringVar() + self.selectedIndex = NotifyStringVar() self.positions = [] self.winners = [] self.losers = [] @@ -436,23 +437,23 @@ class MatchSettingsFrame(RepeatableFrame): def renderContent(self): self.nameLabel = ttk.Label(self) - self.matchID = tk.IntVar() + self.matchID = NotifyIntVar() self.matchID.trace('w', self._updateName) self.matchID.set(self.winfo_toplevel().getNewMatchID(self)) self.winfo_toplevel().bind( '<>', self._updateName, add='+') - self.link = tk.StringVar() + self.link = NotifyStringVar() - self.source = tk.IntVar() + self.source = NotifyIntVar() self.source.trace('w', self._enablePanels) - self.scoreDB = tk.StringVar() - self.scoreRound = tk.IntVar() - self.scoreTable = tk.IntVar() - self.scoreCustom = [tk.StringVar(), tk.StringVar()] - self.scoreNotFinished = tk.IntVar() + self.scoreDB = NotifyStringVar() + self.scoreRound = NotifyNumericVar() + self.scoreTable = NotifyNumericVar() + self.scoreCustom = [NotifyStringVar(), NotifyStringVar()] + self.scoreNotFinished = NotifyIntVar() self.scoreNotFinished.trace('w', self._enablePanels) - self.scoreBoards = tk.IntVar() + self.scoreBoards = NotifyNumericVar() self.winnerPositions = [] self.loserPositions = [] @@ -493,11 +494,11 @@ class MatchSettingsFrame(RepeatableFrame): self.SCORE_SOURCE_DB: [ DBSelectionField(scoreGroup, self.scoreDB, self.scoreDB.get()), ttk.Label(scoreGroup, text='Runda:'), - tk.Spinbox( + NumericSpinbox( scoreGroup, width=3, textvariable=self.scoreRound, from_=1, to=999), ttk.Label(scoreGroup, text='Stół:'), - tk.Spinbox( + NumericSpinbox( scoreGroup, width=3, textvariable=self.scoreTable, from_=1, to=999) ], @@ -505,15 +506,15 @@ class MatchSettingsFrame(RepeatableFrame): ttk.Entry(scoreGroup, textvariable=self.link), # TODO: TC support (Round/Session) #ttk.Label(scoreGroup, text='Sesja:'), - #tk.Spinbox( + #NumericSpinbox( # scoreGroup, #textvariable=self.scoreSession, from_=1, to=999), #ttk.Label(scoreGroup, text='Runda:'), - #tk.Spinbox( + #NumericSpinbox( # scoreGroup, #textvariable=self.scoreRound, from_=1, to=999), ttk.Label(scoreGroup, text='Stół:'), - tk.Spinbox( + NumericSpinbox( scoreGroup, width=3, textvariable=self.scoreTable, from_=1, to=999) ], @@ -528,7 +529,7 @@ class MatchSettingsFrame(RepeatableFrame): ttk.Checkbutton( scoreGroup, variable=self.scoreNotFinished, text='mecz nie został zakończony, rozegrano:'), - tk.Spinbox( + NumericSpinbox( scoreGroup, width=3, textvariable=self.scoreBoards, from_=0, to=999), ttk.Label(scoreGroup, text='rozdań') @@ -684,8 +685,8 @@ class MatchPhaseFrame(ScrollableFrame): self.winfo_toplevel().event_generate('<>', when='tail') def renderContent(self, container): - self.name = tk.StringVar() - self.link = tk.StringVar() + self.name = NotifyStringVar() + self.link = NotifyStringVar() self.previousLink = '' headerFrame = tk.Frame(container) diff --git a/jfr_playoff/gui/frames/network.py b/jfr_playoff/gui/frames/network.py index 7112171..d44ff49 100644 --- a/jfr_playoff/gui/frames/network.py +++ b/jfr_playoff/gui/frames/network.py @@ -7,8 +7,9 @@ from tkinter import ttk import tkMessageBox as tkmb from ...db import PlayoffDB -from ..frames import RepeatableEntry, WidgetRepeater -from ..frames import GuiFrame, ScrollableFrame, getIntVal +from ..frames import RepeatableEntry, WidgetRepeater, NumericSpinbox +from ..frames import GuiFrame, ScrollableFrame +from ..variables import NotifyStringVar, NotifyIntVar, NotifyNumericVar def network_test(connFunction, testLabel): try: @@ -28,7 +29,7 @@ class MySQLConfigurationFrame(GuiFrame): if len(self.host.get().strip()): return { 'host': self.host.get().strip(), - 'port': getIntVal(self.port, default=3306), + 'port': self.port.get(default=3306), 'user': self.user.get().strip(), 'pass': self.pass_.get().strip() } @@ -51,13 +52,13 @@ class MySQLConfigurationFrame(GuiFrame): '<>', when='tail') def renderContent(self): - self.host = tk.StringVar() + self.host = NotifyStringVar() self.host.trace('w', self._changeNotify) - self.port = tk.StringVar() + self.port = NotifyNumericVar() self.port.trace('w', self._changeNotify) - self.user = tk.StringVar() + self.user = NotifyStringVar() self.user.trace('w', self._changeNotify) - self.pass_ = tk.StringVar() + self.pass_ = NotifyStringVar() self.pass_.trace('w', self._changeNotify) self.columnconfigure(0, weight=1) @@ -72,7 +73,7 @@ class MySQLConfigurationFrame(GuiFrame): (ttk.Label(frame, text='Port:')).grid( row=0, column=2, sticky=tk.E) - (tk.Spinbox( + (NumericSpinbox( frame, textvariable=self.port, width=5, from_=0, to=65535)).grid(row=0, column=3, sticky=tk.W) @@ -116,8 +117,8 @@ class GoniecConfigurationFrame(GuiFrame): def test(): goniec = socket.socket() goniec.connect( - (self.host.get().strip(), getIntVal( - self.port, self.DEFAULT_PORT))) + (self.host.get().strip(), + self.port.get(default=self.DEFAULT_PORT))) goniec.close() self.testError = network_test(test, self.testLabel) @@ -126,10 +127,10 @@ class GoniecConfigurationFrame(GuiFrame): tkmb.showerror('Błąd połączenia z Gońcem', self.testError) def renderContent(self): - self.enable = tk.IntVar() + self.enable = NotifyIntVar() self.enable.trace('w', self._enableWidgets) - self.host = tk.StringVar() - self.port = tk.StringVar() + self.host = NotifyStringVar() + self.port = NotifyNumericVar() self.columnconfigure(0, weight=1) @@ -144,7 +145,7 @@ class GoniecConfigurationFrame(GuiFrame): self.hostField.grid(row=1, column=1) (ttk.Label(frame, text='Port:')).grid(row=1, column=2) - self.portField = tk.Spinbox( + self.portField = NumericSpinbox( frame, textvariable=self.port, width=5) self.portField.grid(row=1, column=3) diff --git a/jfr_playoff/gui/frames/team.py b/jfr_playoff/gui/frames/team.py index 90394d0..2a19866 100644 --- a/jfr_playoff/gui/frames/team.py +++ b/jfr_playoff/gui/frames/team.py @@ -5,31 +5,34 @@ from tkinter.font import Font from tkinter import ttk from ..frames import GuiFrame, RepeatableFrame, ScrollableFrame -from ..frames import WidgetRepeater, RepeatableEntry +from ..frames import WidgetRepeater, RepeatableEntry, NumericSpinbox from ..frames import SelectionButton, SelectionFrame, RefreshableOptionMenu -from ..frames import getIntVal, setPanelState +from ..frames import setPanelState +from ..variables import NotifyStringVar, NotifyIntVar, NotifyNumericVar class ManualTeamRow(RepeatableFrame): def renderContent(self): - self.fullname = tk.StringVar() + self.fullname = NotifyStringVar() + self.shortname = NotifyStringVar() + self.flag = NotifyStringVar() + self.position = NotifyNumericVar() + for var in [self.fullname, self.shortname, self.flag, self.position]: + var.trace('w', self._changeNotify) + fullnameField = ttk.Entry(self, width=20, textvariable=self.fullname) fullnameField.grid(row=0, column=0) - self.shortname = tk.StringVar() shortnameField = ttk.Entry(self, width=20, textvariable=self.shortname) shortnameField.grid(row=0, column=1) - self.flag = tk.StringVar() flagField = ttk.Entry(self, width=10, textvariable=self.flag) flagField.grid(row=0, column=2) - self.position = tk.StringVar() positionField = ttk.Entry(self, width=10, textvariable=self.position) positionField.grid(row=0, column=3) - for var in [self.fullname, self.shortname, self.flag, self.position]: - var.trace('w', self._changeNotify) + self._changeNotify(None) def getValue(self): flag = self.flag.get().strip() - position = getIntVal(self.position, None) + position = self.position.get() return [ self.fullname.get().strip(), self.shortname.get().strip(), flag if len(flag) else None, position @@ -162,7 +165,7 @@ class TeamFetchSettingsFrame(GuiFrame): teams['database'] = self.fetchDB.get() if len(self.finishingPositions): teams['final_positions'] = self.finishingPositions - maxTeams = getIntVal(self.fetchLimit) + maxTeams = self.fetchLimit.get() if maxTeams: teams['max_teams'] = maxTeams return teams @@ -176,14 +179,14 @@ class TeamFetchSettingsFrame(GuiFrame): self.fetchDBField.configure(state=tk.NORMAL) def renderContent(self): - self.fetchSource = tk.IntVar() + self.fetchSource = NotifyIntVar() self.fetchSource.trace('w', self._sourceChange) self.fetchSource.trace('w', self._changeNotify) - self.fetchDB = tk.StringVar() + self.fetchDB = NotifyStringVar() self.fetchDB.trace('w', self._changeNotify) - self.link = tk.StringVar() + self.link = NotifyStringVar() self.link.trace('w', self._changeNotify) - self.fetchLimit = tk.StringVar() + self.fetchLimit = NotifyNumericVar() self.fetchLimit.trace('w', self._changeNotify) self.columnconfigure(3, weight=1) @@ -207,7 +210,7 @@ class TeamFetchSettingsFrame(GuiFrame): (ttk.Label(self, text='Pobierz do ')).grid( row=2, column=0, columnspan=2, sticky=tk.W) - (tk.Spinbox( + (NumericSpinbox( self, from_=0, to=9999, width=5, justify=tk.RIGHT, textvariable=self.fetchLimit)).grid( row=2, column=2, sticky=tk.W) @@ -259,7 +262,7 @@ class TeamSettingsFrame(ScrollableFrame): self.teams = self.winfo_toplevel().getTeams() def renderContent(self, container): - self.teamFormat = tk.IntVar() + self.teamFormat = NotifyIntVar() self.teamFormat.trace('w', self._enablePanels) self.teamFormat.trace('w', self._changeNotify) @@ -324,7 +327,7 @@ class TeamAliasRow(RepeatableFrame): def renderContent(self): self.columnconfigure(0, weight=0) self.columnconfigure(1, weight=1) - self.teamName = tk.StringVar() + self.teamName = NotifyStringVar() list = TeamList(self, self.teamName, self.teamName.get()) list.configure(width=20) list.grid( @@ -384,10 +387,10 @@ class TeamPreviewFrame(ScrollableFrame): team[2] = '' self.teamList.insert('', tk.END, values=team, tag=idx) if idx >= len(self.tieFields): - self.tieValues.append(tk.StringVar()) + self.tieValues.append(NotifyNumericVar()) self.tieValues[idx].trace('w', self._tieValueChangeNotify) self.tieFields.append( - tk.Spinbox( + NumericSpinbox( container, from_=0, to=9999, width=5, font=Font(size=10), textvariable=self.tieValues[idx])) @@ -429,7 +432,7 @@ class TeamPreviewFrame(ScrollableFrame): def getTieConfig(self): teams = self._getTeams() - ties = [(teams[idx], getIntVal(val, 0)) + ties = [(teams[idx], val.get(default=0)) for idx, val in enumerate(self.tieValues)] return [team[0][0] for team in sorted(ties, key=lambda t: t[1]) diff --git a/jfr_playoff/gui/frames/translations.py b/jfr_playoff/gui/frames/translations.py index 2429bfe..3ba660f 100644 --- a/jfr_playoff/gui/frames/translations.py +++ b/jfr_playoff/gui/frames/translations.py @@ -7,13 +7,15 @@ from tkinter import ttk from ..frames import RepeatableFrame, WidgetRepeater, ScrollableFrame from ...i18n import PLAYOFF_I18N_DEFAULTS +from ..variables import NotifyStringVar class TranslationRow(RepeatableFrame): def renderContent(self): - self.key = tk.StringVar() + self.key = NotifyStringVar() + self.value = NotifyStringVar() + (ttk.Entry(self, textvariable=self.key, width=40)).pack( side=tk.LEFT, fill=tk.BOTH, expand=True) - self.value = tk.StringVar() (ttk.Entry(self, textvariable=self.value, width=80)).pack( side=tk.RIGHT, fill=tk.BOTH, expand=True) diff --git a/jfr_playoff/gui/frames/visual.py b/jfr_playoff/gui/frames/visual.py index 0762e37..3e09445 100644 --- a/jfr_playoff/gui/frames/visual.py +++ b/jfr_playoff/gui/frames/visual.py @@ -5,9 +5,10 @@ from tkinter import ttk import tkColorChooser as tkcc from ..frames import GuiFrame, RepeatableFrame, ScrollableFrame -from ..frames import WidgetRepeater, getIntVal -from ..frames import SelectionFrame, RefreshableOptionMenu +from ..frames import WidgetRepeater +from ..frames import SelectionFrame, RefreshableOptionMenu, NumericSpinbox from ..frames.team import TeamSelectionButton +from ..variables import NotifyStringVar, NotifyIntVar, NotifyNumericVar class VisualSettingsFrame(GuiFrame): DEFAULT_VALUES = { @@ -29,20 +30,20 @@ class VisualSettingsFrame(GuiFrame): } def renderContent(self): - self.startingPositionIndicators = tk.IntVar() - self.finishingPositionIndicators = tk.IntVar() - self.boxWidth = tk.IntVar() - self.boxHeight = tk.IntVar() - self.boxMargin = tk.IntVar() - self.shortenTeamNames = tk.IntVar() - self.teamNameLength = tk.IntVar() - self.teamNameEllipsis = tk.StringVar() - self.teamNamePredict = tk.IntVar() - self.teamNamePlaceholder = tk.StringVar() - self.teamNameSortPredictions = tk.IntVar() - self.teamLabelSeparator = tk.StringVar() - self.teamNameSeparator = tk.StringVar() - self.teamNamePrefix = tk.StringVar() + self.startingPositionIndicators = NotifyIntVar() + self.finishingPositionIndicators = NotifyIntVar() + self.boxWidth = NotifyNumericVar() + self.boxHeight = NotifyNumericVar() + self.boxMargin = NotifyNumericVar() + self.shortenTeamNames = NotifyIntVar() + self.teamNameLength = NotifyNumericVar() + self.teamNameEllipsis = NotifyStringVar() + self.teamNamePredict = NotifyIntVar() + self.teamNamePlaceholder = NotifyStringVar() + self.teamNameSortPredictions = NotifyIntVar() + self.teamLabelSeparator = NotifyStringVar() + self.teamNameSeparator = NotifyStringVar() + self.teamNamePrefix = NotifyStringVar() indicatorsFrame = ttk.LabelFrame(self, text='Znaczniki pozycji:') indicatorsFrame.grid(row=0, column=0, sticky=tk.W+tk.E+tk.N+tk.S) @@ -64,19 +65,19 @@ class VisualSettingsFrame(GuiFrame): variable=self.finishingPositionIndicators)).grid( row=1, column=0, sticky=tk.W) - (tk.Spinbox( - dimensionsFrame, width=5, justify=tk.RIGHT, from_=1, to=999, + (NumericSpinbox( + dimensionsFrame, width=5, from_=1, to=999, textvariable=self.boxWidth)).grid( row=0, column=0, sticky=tk.W) (ttk.Label(dimensionsFrame, text='x')).grid(row=0, column=1) - (tk.Spinbox( - dimensionsFrame, width=5, justify=tk.RIGHT, from_=1, to=999, + (NumericSpinbox( + dimensionsFrame, width=5, from_=1, to=999, textvariable=self.boxHeight)).grid( row=0, column=2, sticky=tk.W) (ttk.Label(dimensionsFrame, text='odstępy')).grid( row=1, column=0, columnspan=2, sticky=tk.E) - (tk.Spinbox( - dimensionsFrame, width=5, justify=tk.RIGHT, from_=1, to=999, + (NumericSpinbox( + dimensionsFrame, width=5, from_=1, to=999, textvariable=self.boxMargin)).grid( row=1, column=2, sticky=tk.W) @@ -84,8 +85,8 @@ class VisualSettingsFrame(GuiFrame): teamNamesFrame, text='skracaj do', variable=self.shortenTeamNames)).grid( row=0, column=0, columnspan=2) - nameLength = tk.Spinbox( - teamNamesFrame, width=5, justify=tk.RIGHT, from_=1, to=999, + nameLength = NumericSpinbox( + teamNamesFrame, width=5, from_=1, to=999, textvariable=self.teamNameLength) nameLength.grid(row=0, column=2, sticky=tk.W) lengthLabel = ttk.Label(teamNamesFrame, text='znaków') @@ -197,22 +198,23 @@ class MatchList(RefreshableOptionMenu): class BoxPositionFrame(RepeatableFrame): def renderContent(self): - self.match = tk.StringVar() - self.vertical = tk.IntVar() - self.horizontal = tk.IntVar() + self.match = NotifyStringVar() + self.vertical = NotifyNumericVar() + self.horizontal = NotifyNumericVar() self.matchBox = MatchList(self, self.match) self.matchBox.configure(width=20) self.matchBox.grid(row=0, column=0) + (ttk.Label(self, text=' w pionie:')).grid(row=0, column=1) - (tk.Spinbox( + (NumericSpinbox( self, textvariable=self.vertical, from_=0, to=9999, - width=5, justify=tk.RIGHT)).grid( + width=5)).grid( row=0, column=2) (ttk.Label(self, text=' w poziomie (-1 = automatyczna):')).grid( row=0, column=3) - (tk.Spinbox( + (NumericSpinbox( self, textvariable=self.horizontal, from_=-1, to=9999, - width=5, justify=tk.RIGHT)).grid( + width=5)).grid( row=0, column=4) self.setValue([]) @@ -262,19 +264,20 @@ class LineStyle(GuiFrame): self.colourBtn.configure(bg=colour) def renderContent(self): + self.hOffset = NotifyNumericVar() + self.vOffset = NotifyNumericVar() + (ttk.Label(self, text='kolor:')).grid(row=0, column=0) self.colourBtn = tk.Button(self, width=2, command=self._selectColour) self.colourBtn.grid(row=0, column=1) (ttk.Label(self, text='margines w poziomie:')).grid(row=0, column=2) - self.hOffset = tk.StringVar() - (tk.Spinbox( + (NumericSpinbox( self, textvariable=self.hOffset, from_=-50, to=50, - width=5, justify=tk.RIGHT)).grid(row=0, column=3) + width=5)).grid(row=0, column=3) (ttk.Label(self, text='margines w pionie:')).grid(row=0, column=4) - self.vOffset = tk.StringVar() - (tk.Spinbox( + (NumericSpinbox( self, textvariable=self.vOffset, from_=-50, to=50, - width=5, justify=tk.RIGHT)).grid(row=0, column=5) + width=5)).grid(row=0, column=5) def setValue(self, value): self._setColour(value[0]) @@ -345,8 +348,8 @@ class PositionStyleFrame(RepeatableFrame): self.positions = values def renderContent(self): - self.name = tk.StringVar() - self.description = tk.StringVar() + self.name = NotifyStringVar() + self.description = NotifyStringVar() self.columnconfigure(1, weight=1) self.columnconfigure(5, weight=1) diff --git a/jfr_playoff/gui/tabs.py b/jfr_playoff/gui/tabs.py index 1656fc7..a12a993 100644 --- a/jfr_playoff/gui/tabs.py +++ b/jfr_playoff/gui/tabs.py @@ -7,12 +7,13 @@ from tkinter import ttk import tkFileDialog as tkfd import tkMessageBox as tkmb -from .frames import TraceableText +from .frames import TraceableText, NumericSpinbox from .frames.match import * from .frames.network import * from .frames.team import * from .frames.translations import * from .frames.visual import * +from .variables import NotifyStringVar, NotifyIntVar, NotifyNumericVar from ..data import PlayoffData from ..db import PlayoffDB @@ -46,12 +47,12 @@ class MainSettingsTab(PlayoffTab): return 'Główne ustawienia' def initData(self): - self.outputPath = tk.StringVar() - self.pageTitle = tk.StringVar() - self.pageLogoh = tk.StringVar() - self.refresh = tk.IntVar() + self.outputPath = NotifyStringVar() + self.pageTitle = NotifyStringVar() + self.pageLogoh = NotifyStringVar() + self.refresh = NotifyIntVar() self.refresh.trace('w', self._updateRefreshFields) - self.refreshInterval = tk.StringVar() + self.refreshInterval = NotifyNumericVar() def _chooseOutputPath(self): currentPath = self.outputPath.get() @@ -135,7 +136,7 @@ class MainSettingsTab(PlayoffTab): command=self._updateRefreshFields, variable=self.refresh)).grid( row=0, column=0) (ttk.Label(refreshPanel, text='co:')).grid(row=0, column=1) - self.intervalField = tk.Spinbox( + self.intervalField = NumericSpinbox( refreshPanel, from_=30, to=3600, width=5, justify=tk.RIGHT, textvariable=self.refreshInterval) self.intervalField.grid(row=0, column=2) diff --git a/jfr_playoff/gui/variables.py b/jfr_playoff/gui/variables.py new file mode 100644 index 0000000..abb3cc1 --- /dev/null +++ b/jfr_playoff/gui/variables.py @@ -0,0 +1,24 @@ +#coding=utf-8 + +import tkinter as tk + +class NotifyVar(tk.Variable): + def __init__(self, *args, **kwargs): + tk.Variable.__init__(self, *args, **kwargs) + self.trace('w', self._onChange) + + def _onChange(self, *args): + self._root.event_generate('<>', when='tail') + +class NotifyStringVar(NotifyVar, tk.StringVar): + pass + +class NotifyIntVar(NotifyVar, tk.IntVar): + pass + +class NotifyNumericVar(NotifyStringVar): + def get(self, default=None): + try: + return int(str(NotifyStringVar.get(self)).strip()) + except ValueError: + return default -- cgit v1.2.3