def __init__(self, widget: tkinter.Widget, text: str) -> None: widget.bind("<Enter>", self.enter, add=True) widget.bind("<Leave>", self.leave, add=True) widget.bind("<Motion>", self.motion, add=True) self.widget = widget self.got_mouse = False self.text = text # can be changed after creating tooltip manager
def __init__(self, _master_: Widget, _scene_: SceneFrame): _master_.update() super().__init__(_master_, borderwidth=2, relief="groove") self._master = _master_ self._scene = _scene_ self._build() pass
def __init__(self, widget: tkinter.Widget) -> None: widget.bind('<Enter>', self.enter, add=True) widget.bind('<Leave>', self.leave, add=True) widget.bind('<Motion>', self.motion, add=True) self.widget = widget self.got_mouse = False self.text: Optional[str] = None
def update_image(widget: tk.Widget, img, encode_mode: int = cv2.IMREAD_GRAYSCALE) -> None: """ 表示画像の更新を行う。 :param widget 画像を表示対象 :param img イメージデータ :param encode_mode 出力画像形式 カラー / グレースケール note:ImageData.encode2PNMを使っている理由はexeファイルのサイズ削減のため。 Pillowに依存しないことで1MB、実行ファイルサイズが削減されます。 """ assert img is not None # 画像出力用 widget.np = img ct() ext = { cv2.IMREAD_GRAYSCALE: '.PGM', cv2.IMREAD_COLOR: '.PPM' }.get(encode_mode) # PGMまたはPBM形式に変換する。 # GC対象にならないように参照を保持 #ext = ".png" widget.src = tk.PhotoImage(data=ImageData.encode2PNM(img, ext)) ct() widget.configure(image=widget.src) ct()
def set_visible(widget: tk.Widget, visible: bool = False) -> None: """ ウィンドウの表示/非表示を行う。 """ if visible: widget.deiconify() else: widget.withdraw()
def _place_widget(widget: tkinter.Widget, row: int, column: int, columnspan: int, padx: int, pady: int, sticky: int): """Place widget on the windows (short hand for the grid command)""" widget.grid(row=row, column=column, columnspan=columnspan, padx=padx, pady=pady, sticky=sticky)
def bind_all(widget: tk.Widget, modifier: str = "", letter: str = "", callback=None) -> None: widget.bind_all('<{0}-{1}>'.format(modifier, letter.upper()), callback) # numeric letter multi assign check. if not letter.isdecimal(): widget.bind_all('<{0}-{1}>'.format(modifier, letter.lower()), callback)
def style_menu(widget: tk.Widget) -> None: style = ttk.Style() bg = style.lookup(".", "background") fg = style.lookup(".", "foreground") abg = style.lookup(".", "lightcolor") if not abg: abg = bg widget.config( background=bg, foreground=fg, activebackground=abg, activeforeground=fg, bd=0 )
def __init__(self, master=None, cnf={}, **kw): cnf = _cnfmerge((cnf, kw)) self.widgetName = '__dialog__' Widget._setup(self, master, cnf) self.num = self.tk.getint( self.tk.call('tk_dialog', self._w, cnf['title'], cnf['text'], cnf['bitmap'], cnf['default'], *cnf['strings'])) try: Widget.destroy(self) except TclError: pass
def add_widget(self, widget: tk.Widget, index: int=None): # modify the index so that the start and abort # buttons are always at the end of the list if index is None: self.widgets.insert(-2, widget) else: self.widgets.insert(index, widget) for i, widget in enumerate(self.widgets): widget.grid_forget() widget.grid(row=i, sticky='ew')
def add_widget(self, widget: tk.Widget, index: int=None): if index is None: logger.debug('adding widget {}'.format(widget)) self.widgets.append(widget) else: logger.debug('adding widget {} at index {}'.format(widget, index)) self.widgets.insert(index, widget) for i, widget in enumerate(self.widgets): widget.grid_forget() widget.grid(row=i, sticky='ew')
def progress_step(progress_widget: tk.Widget, increment: int = 1): '''Increment the progress bar. Arguments: progress_widget {ttk.Progressbar} -- The progress bar to be initialized. Keyword Arguments: increment {int} -- The incremental step size to use. (default: {1}) ''' progress_widget.step(increment) progress_widget.update_idletasks()
def grid(w: Widget, row, col, colspan=1, rowspan=1, pad=5, **kw): d = { 'row': row, 'column': col, 'columnspan': colspan, 'rowspan': rowspan, 'padx': pad, 'pady': pad, 'sticky': 'ensw' } w.grid(**{**d, **kw}) return w
def lock(widget: tk.Widget, state: str): """ Either lock or unlock a widget based on the state string. :param widget: recursively lock/unlock if its a frame otherwise change the config to the specified state :param state: state to set the widgets to """ if "TFrame" in widget.winfo_class(): for child in widget.winfo_children(): lock(child, state) else: widget.config(state=state)
def widget_recursive_enabler(widget: tk.Widget, enable: bool): '''Enable/Disable a TK widget and all its children.''' # TODO: Detect if tkwidget or ttk if enable: state = ['!disabled'] else: state = ['disabled'] for child in widget.winfo_children(): widget_recursive_enabler(child, enable=enable) widget.state(state)
def grid(widget: Widget, row: int, column: int, r=1, c=1): """Syntax candy for common use of grid geometry management method. always has sticky set to "nsew". Args: widget: the widget to be placed. row: row number (0 and up). column: column number (0 and up). r: optional row span c: optional column span """ widget.grid(row=row, column=column, rowspan=r, columnspan=c, sticky="nsew")
def unbind_ci(widget: tk.Widget, all_: bool = False, *, modifier: str = '', letter: str, callback=None): if modifier and letter: modifier += '-' if all_: widget.unbind_all(f'<{modifier}{letter.lower()}>') widget.unbind_all(f'<{modifier}{letter.upper()}>') else: widget.unbind(f'<{modifier}{letter.lower()}>', callback) widget.unbind(f'<{modifier}{letter.upper()}>', callback)
def style_listbox(widget: tk.Widget) -> None: style = ttk.Style() bg = style.lookup(".", "background") fg = style.lookup(".", "foreground") bc = style.lookup(".", "bordercolor") if not bc: bc = "black" widget.config( background=bg, foreground=fg, highlightthickness=1, highlightcolor=bc, highlightbackground=bc, bd=0, )
def position_absolute(self, widget: tkinter.Widget, x_position: int, y_position: int, x_size: int, y_size: int) \ -> None: """ Position a widget absolutely in a grid layout :param widget: the widget to be positioned :param x_position: the horizontal position of the widget in the grid :param y_position: the vertical position of the widget in the grid :param x_size: the width of the widget in the grid layout :param y_size: the width of the widget in the grid layout :return: void """ widget.grid(column=x_position, row=y_position, columnspan=x_size, rowspan=y_size, sticky=W + E + N + S) if self.rowcounter < y_position + y_size: self.rowcounter = y_position + y_size if self.columncounter < x_position + x_size: self.columncounter = x_position + x_size
def create_tooltip(widget: tk.Widget, text: str): """ Create a tooltip with text that is shown when the user hovers over widget. """ tool_tip = ToolTip(widget) # noinspection PyUnusedLocal def enter(tk_event: tk.Event): tool_tip.show_tooltip(text) # noinspection PyUnusedLocal def leave(tk_event: tk.Event): tool_tip.hide_tooltip() widget.bind('<Enter>', enter) widget.bind('<Leave>', leave)
def pack(self, w: tk.Widget): rtn = w.grid(padx=PAD, pady=PAD, row=int(self.__counter / self.__width), column=self.__counter % self.__width) self.__counter += 1 return rtn
def toggle_state(self, item: tk.Widget, state: bool = False): counter = self._get_counter(item) if not state: if counter.inc() == 1: if not isinstance(item, tuple): item.configure(state=tk.DISABLED) else: if isinstance(item[0], tk.Menu): item[0].entryconfig(item[1], state=tk.DISABLED) else: if counter.dec() == 0: if not isinstance(item, tuple): item.configure(state=tk.NORMAL) else: if isinstance(item[0], tk.Menu): item[0].entryconfig(item[1], state=tk.NORMAL)
def bind_all(widget: tk.Widget, modifier: str = "", letter: str = "", callback=None) -> None: """ Keyboard Shortcut Assign. :param widget:割り当てるウィジット :param modifier:キーコード修飾子 Ctrl, Shift, Altなど :param letter:割当文字 :param callback:イベント発生時に呼び出されるコールバック :return: """ widget.bind_all('<{0}-{1}>'.format(modifier, letter.upper()), callback) # numeric letter multi assign check. if not letter.isdecimal(): widget.bind_all('<{0}-{1}>'.format(modifier, letter.lower()), callback)
def set_widget_geometry(self, widget: tk.Widget, settings: ET.Element): '''Apply window geometry settings given in the XML element. Arguments: widget {tk.Widget} -- The widget instance. settings {ET.Element} -- The widget Settings XML Element. ''' options = dict() geometry = settings.find('Geometry') padding = geometry.find('Padding') if padding is not None: options.update(self.reference.resolve(padding.attrib)) placement = geometry[0] options.update(self.reference.resolve(placement.attrib)) if 'Grid' in placement.tag: widget.grid(**options) elif 'Pack' in placement.tag: widget.pack(**options) pass
def _setup_geometry(self, obj: tk.Widget, geom: str): geom_match = self.__geom_re.match(geom) if not geom_match: raise RuntimeError(f"Invalid geometry: '{geom}'") row_pattern = geom_match["row"] column_pattern = geom_match["column"] if geom_match["sticky"] is not None: obj.grid(sticky=geom_match["sticky"]) row = self._parse_axis_configuration(row_pattern) column = self._parse_axis_configuration(column_pattern) obj.grid( column=column.position, row=row.position, rowspan=1 + row.span, columnspan=1 + column.span, ) obj.master.rowconfigure(row.position, weight=row.weight) obj.master.columnconfigure(column.position, weight=column.weight)
def bind_tab_key(widget: tkinter.Widget, on_tab: Callable[['tkinter.Event[Any]', bool], BreakOrNone], **bind_kwargs: Any) -> None: """A convenience function for binding Tab and Shift+Tab. Use this function like this:: def on_tab(event, shifted): # shifted is True if the user held down shift while pressing # tab, and False otherwise ... utils.bind_tab_key(some_widget, on_tab, add=True) The ``event`` argument and ``on_tab()`` return values are treated just like with regular bindings. Binding ``'<Tab>'`` works just fine everywhere, but binding ``'<Shift-Tab>'`` only works on Windows and Mac OSX. This function also works on X11. """ # there's something for this in more_functools, but it's a big # dependency for something this simple imo def callback(shifted: bool, event: 'tkinter.Event[tkinter.Misc]') -> BreakOrNone: return on_tab(event, shifted) if widget.tk.call('tk', 'windowingsystem') == 'x11': # even though the event keysym says Left, holding down the right # shift and pressing tab also works :D shift_tab = '<ISO_Left_Tab>' else: shift_tab = '<Shift-Tab>' widget.bind('<Tab>', functools.partial(callback, False), **bind_kwargs) # bindcheck: ignore widget.bind(shift_tab, functools.partial(callback, True), **bind_kwargs) # bindcheck: ignore
def __init__(self, widget: Widget, text: str, side: str = 'n', **kwargs): """\ Parameters ---------- widget : Widget The parent widget text : str The tooltip text side : str, optional (default is "n") Which side of the parent widget to show the tooltip on **kwargs : dict, optional (default is justify="left", padx=1, pady=1) tkLabel Keyword Arguments for the tooltip """ # verify value if side and side.lower() not in list('nsew'): raise ValueError('<side> parameter must be ' 'one of "n", "s", "e", or "w"') # init vars self._wgt = widget self._side = side.lower() kwargs.update(justify=kwargs.pop('justify', 'left'), padx=kwargs.pop('padx', 1), pady=kwargs.pop('pady', 1)) # create win Toplevel.__init__(self, master=widget) self.attributes("-alpha", 0.75) self.overrideredirect(True) # create lbl self._lbl = Label(master=self, text=text, **kwargs) self._lbl.pack() self.update_idletasks() self._tw = self.winfo_reqwidth() self._th = self.winfo_reqheight() self.withdraw() widget.bind("<Enter>", self.enter) widget.bind("<Leave>", self.close)
def apply_class_bindings(window: tkinter.Widget): """Add class level event bindings in application""" for className in ["TEntry", "TSpinbox", "TCombobox"]: window.bind_class( className=className, sequence="<Configure>", func=on_disabled_readonly_state, add="+" ) for sequence in ["<Control-a>", "<Control-A>"]: window.bind_class( className=className, sequence=sequence, func=on_select_all ) window.unbind_class("TButton", "<Key-space>") window.bind_class("TButton", "<Key-Return>", lambda event: event.widget.invoke())
def _create_edit_menu(master: Widget) -> Menu: menu = Menu(master, tearoff=0) menu.add_command(label="Undo", command=lambda: master.focus_get().edit_undo(), underline=0, accelerator=_KEYS["undo"][0]) menu.add_command(label="Redo", command=lambda: master.focus_get().edit_redo(), underline=0, accelerator=_KEYS["redo"][0]) menu.add_separator() menu.add_command( label="Cut", command=lambda: master.focus_get().event_generate("<<Cut>>"), underline=2, accelerator=_KEYS["cut"][0]) menu.add_command( label="Copy", command=lambda: master.focus_get().event_generate("<<Copy>>"), underline=0, accelerator=_KEYS["copy"][0]) menu.add_command( label="Paste", command=lambda: master.focus_get().event_generate("<<Paste>>"), underline=0, accelerator=_KEYS["paste"][0]) menu.add_separator() menu.add_command( label="Delete", command=lambda: master.focus_get().delete(SEL_FIRST, SEL_LAST), underline=0, accelerator=_KEYS["delete"][0]) def before(): text = master.focus_get() if not isinstance(text, Text): for i in 0, 1, 3, 4, 5, 7: menu.entryconfigure(i, state=DISABLED) else: menu.entryconfigure(0, state=_to_state(text.edit("canundo"))) menu.entryconfigure(1, state=_to_state(text.edit("canredo"))) has_selection = text.tag_ranges(SEL) != () for i in 3, 4, 7: menu.entryconfigure(i, state=_to_state(has_selection)) try: master.clipboard_get() menu.entryconfigure(5, state=NORMAL) except TclError: menu.entryconfigure(5, state=DISABLED) menu.configure(postcommand=before) return menu
def _move(self): tk_main_w = Widget.nametowidget(self, '.') coord_x = tk_main_w.winfo_x() + 250 coord_y = tk_main_w.winfo_y() + self.__coord_y + 150 self.menu = Menu(self, bg=config.colors["BG"], activebackground=config.colors["TV_BG_HOVER"], activeforeground=config.colors["FG"], tearoff=False) for playlist in config.user_config["Playlists"]: if playlist != config.general["playlist"]: #https://stackoverflow.com/questions/11723217/python-lambda-doesnt-remember-argument-in-for-loop func_get_set_playlist = lambda playlist=playlist: self.__move( playlist) self.menu.add_command(label=playlist, command=func_get_set_playlist) self.menu.tk_popup(coord_x, coord_y)