Соответствие ширины OptionMenu и Button (и изображений с изменяемым размером в расширяемых контейнерах)Python

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Соответствие ширины OptionMenu и Button (и изображений с изменяемым размером в расширяемых контейнерах)

Сообщение Anonymous »

У меня есть OptionMenu и кнопка в соседних строках одного и того же столбца сетки. Я не хочу, чтобы сетка управляла размером этих виджетов, потому что она может сделать виджеты слишком широкими. Вместо этого я бы хотел, чтобы OptionMenu и Button имели фиксированный размер — максимальную ширину Button, ширину OptionMenu и ширину всех пунктов меню. Но у меня с этим проблемы.
Ширина и высота OptionMenu и Button изначально равны 1, поэтому сначала я должен связать , чтобы позволить геометрии сетки Менеджер сообщит мне желаемые размеры. Чтобы предотвратить бесконечный цикл, я немедленно отвязываю событие в обработчике.
Затем я могу вычислить ширину всех виджетов либо в пикселях, либо в текстовых единицах. Если я устанавливаю максимальную ширину в обработчике, я обнаруживаю, что «дескриптор» OptionMenu добавляет немного ширины, поэтому ширины кнопок и OptionMenu не совпадают.
Это вынуждает меня вкладывать друг в друга виджеты OptionMenu и Button внутри собственных фреймов (которые, в свою очередь, находятся внутри сетки). Затем я упаковываю OptionMenu и Button для расширения, но отключаю распространение пакетов в кадре. Идея состоит в том, чтобы установить ширину рамки и заставить вложенные виджеты расширяться до заполнения.
К сожалению, менеджер геометрии сетки сообщает моему обработчику, что OptionMenu и Button теперь запрашивают пространство размером 1x1 пиксель. , поскольку распространение пакетов отключено.
Далее я начал с нуля. Там, где будут OptionMenu и Button, я поместил фрейм с размахом строк, равным 2; Содержимое фрейма также управляется (вложенным) менеджером геометрии сетки. Рамка липкая="w"; он уменьшится, чтобы соответствовать своему содержимому. Содержимое липкое="ew"; они будут заполняться до одинакового размера.
Это работает хорошо, за исключением того, что там, где текст в столбцах одной строки будет иметь общую базовую линию, менеджер геометрии вложенной сетки не разделяет базовые линии с родительским менеджер геометрии сетки. Например, текст метки в первом столбце больше не имеет общей базовой линии с текстом OptionMenu во втором столбце. Вместо этого базовая линия текста метки в первом столбце теперь выровнена по нижней части OptionMenu.
Как это исправить?
Для Например, здесь я переместил метку «Ячейка (0,0)» во внутреннюю сетку. Это позволяет мне выровнять текст, но я теряю возможность центрировать вложенные столбцы внутри внешних столбцов.
#!/usr/bin/env python3

import tkinter as tk
import tkinter.font
import tkinter.scrolledtext

import PIL.Image
import PIL.ImageTk

class App:
options = ["short", "really really really really long"]
unselected = ""

def __init__(self, parent, **kwargs):
title = parent.winfo_toplevel().title()
font = tk.font.Font(family="Arial", size=12, weight="bold")

# Create a frame for the entire window
frame = tk.Frame(parent, **kwargs)
frame.pack(fill=tk.BOTH, expand=True)

# Set the title label from the window title
title_label = tk.Label(frame, text=title, font=font)
title_label.grid(row=0, columnspan=2, padx=10, pady=10)

# Load the logos
logo1_image = PIL.Image.new("RGB", (200,200), (0,255,0))
logo2_image = PIL.Image.new("RGB", (200,200), (255,0,0))

logo1_label = tk.Label(frame, borderwidth=0)
logo2_label = tk.Label(frame, borderwidth=0)

# TODO:
# I'm seeing slow-motion resize on large resizes. I believe that
# multiple resizes are being queued, but I can't cancel that queue. I
# need to make this callback schedule a cancellable callback that then
# resizes.
logo1_label.bind\
( ""
, lambda e, i=logo1_image, w=logo1_label: self.resizeimage(e, i, w)
)
logo2_label.bind\
( ""
, lambda e, i=logo2_image, w=logo2_label: self.resizeimage(e, i, w)
)

logo1_label.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
logo2_label.grid(row=1, column=1, padx=10, pady=10, sticky="nsew")

# Create a frame for interactive elements
#input_frame = tk.Frame(frame)
input_frame = tk.Frame(frame, bg="red")
input_frame.grid(row=2, columnspan=2)
input_frame.grid_columnconfigure(0, weight=1, uniform="column")
input_frame.grid_columnconfigure(1, weight=1, uniform="column")

# Label for cell (0,0)
c00_label = tk.Label\
(input_frame, font=font, text="cell (0,0)")
c00_label.grid(row=0, column=0, padx=10, pady=10, sticky="ew")

# Create the OptionMenu
options_var = tk.StringVar()
options_var.set(self.unselected)

options = tk.OptionMenu(input_frame, options_var, *self.options)
options.configure(font=font)
options["menu"].configure(font=font)
options.grid(row=0, column=1, padx=10, pady=10, sticky="ew")

# Create the Button
button = tk.Button\
( input_frame
, font=font, text="implement option"
)
button.grid(row=1, column=1, padx=10, pady=(0,0), sticky="ew")

# Create the labels for the 3rd row
c30_label = tk.Label\
(frame, font=font, text="cell (3,0)")
c30_label.grid(row=3, column=0, padx=10, pady=10, sticky="ew")

c31_label = tk.Label\
(frame, font=font, text="cell (3,1)")
c31_label.grid(row=3, column=1, padx=10, pady=10, sticky="ew")

text = tk.scrolledtext.ScrolledText\
(frame, state=tk.DISABLED, font=font)
text.grid(row=4, columnspan=2, padx=10, pady=10, sticky="nsew")

frame.grid_columnconfigure(0, weight=1, minsize=100)
frame.grid_columnconfigure(1, weight=1, minsize=100)
frame.grid_rowconfigure(0, weight=0)
frame.grid_rowconfigure(1, weight=1, minsize=100)
frame.grid_rowconfigure(2, weight=0)
frame.grid_rowconfigure(3, weight=0)
frame.grid_rowconfigure(4, weight=4)

@staticmethod
def resizeimage(event, image, widget):
image = image.copy()
image.thumbnail\
( (event.width, event.height)
, resample=PIL.Image.Resampling.BILINEAR
, reducing_gap=None
)
image = PIL.ImageTk.PhotoImage(image)
widget.config(image=image)
# Images are not referenced by tkinter
widget.image = image
#widget.unbind("")

def main():
root = tk.Tk()
root.title("Helpful Title")

app = App(root)

root.mainloop()

if __name__ == "__main__":
main()

Изменить. Вот наиболее рабочая версия варианта обратного вызова с описанными выше фреймами. Сначала вы упаковываете данные в кадр с включенным распространением. В обратном вызове явно установите высоту, равную текущей высоте, и ширину, равную максимальной ширине всех содержащихся виджетов, затем отключите распространение обратного вызова.
К сожалению, это Версия имеет две проблемы:
  • Измерение меток OptionMenu ошибочно, поэтому размер кнопок слишком мал, чтобы соответствовать действительно длинному пункту меню.
  • Изменение размера изображений вызывает бурю обратных вызовов; Я не знаю почему!
Как мне решить эти проблемы?
#!/usr/bin/env python3

import tkinter as tk
import tkinter.font
import tkinter.scrolledtext

import PIL.Image
import PIL.ImageTk

class App:
options = ["short", "really really really really really long"]
unselected = ""

def __init__(self, parent, **kwargs):
title = parent.winfo_toplevel().title()
font = tk.font.Font(family="Arial", size=12, weight="bold")

# Create a frame for the entire window
frame = tk.Frame(parent, **kwargs)
frame.pack(fill=tk.BOTH, expand=True)

# Set the title label from the window title
title_label = tk.Label(frame, text=title, font=font)
title_label.grid(row=0, columnspan=2, padx=10, pady=10)

# Load the logos
logo1_image = PIL.Image.new("RGB", (200,200), (0,255,0))
logo2_image = PIL.Image.new("RGB", (200,200), (255,0,0))

logo1_label = tk.Label(frame, bg="orange", borderwidth=0)
logo2_label = tk.Label(frame, bg="blue", borderwidth=0)

logo1_label.resize_count = 0
logo2_label.resize_count = 0
logo1_label.resize_id = None
logo2_label.resize_id = None
print("logo1_label: ", logo1_label)
print("logo2_label: ", logo2_label)

# TODO:
# I'm seeing slow-motion resize on large resizes. I believe that
# multiple resizes are being queued, but I can't cancel the queue. I
# need to make this callback schedule a cancellable callback that then
# resizes.
logo1_label.bind\
("", lambda e, i=logo1_image: self.onconfigure_image(e, i))
logo2_label.bind\
("", lambda e, i=logo2_image: self.onconfigure_image(e, i))

logo1_label.grid(row=1, column=0, padx=0, pady=0, sticky="nsew")
logo2_label.grid(row=1, column=1, padx=0, pady=0, sticky="nsew")

# Label for cell (2,0)
c00_label = tk.Label\
(frame, font=font, text="cell (2,0)")
c00_label.grid(row=2, column=0, padx=10, pady=10, sticky="ew")

# Create the OptionMenu
options_var = tk.StringVar()
options_var.set(self.unselected)

options_frame = tk.Frame(frame, bg="red")

options = tk.OptionMenu(options_frame, options_var, *self.options)
options.configure(font=font)
options["menu"].configure(font=font)

options.pack(fill=tk.BOTH, expand=True)
options_frame.grid(row=2, column=1, padx=10, pady=10)

# Create the Button
button_frame = tk.Frame(frame, bg="red")

button = tk.Button\
(button_frame, font=font, text="implement option")
button.pack(fill=tk.BOTH, expand=True)
button_frame.grid(row=3, column=1, padx=10, pady=(0,0))

button.bind("", self.onconfigure_button)

# not sure why I can't get the font from the widget, ie:
# font = tk.font.nametofont(self.options.cget("font"))
# *** _tkinter.TclError: named font font1 does not already exist
self.font = font
self.options_frame = options_frame
self.button_frame = button_frame
self.options = options
self.button = button

# Create the labels for the 4th row
c30_label = tk.Label\
(frame, font=font, text="cell (4,0)")
c30_label.grid(row=4, column=0, padx=10, pady=10, sticky="ew")

c31_label = tk.Label\
(frame, font=font, text="cell (4,1)")
c31_label.grid(row=4, column=1, padx=10, pady=10, sticky="ew")

text = tk.scrolledtext.ScrolledText\
(frame, state=tk.DISABLED, font=font)
text.grid(row=5, columnspan=2, padx=10, pady=10, sticky="nsew")

frame.grid_columnconfigure(0, weight=1, minsize=100, uniform="column")
frame.grid_columnconfigure(1, weight=1, minsize=100, uniform="column")
frame.grid_rowconfigure(0, weight=0)
frame.grid_rowconfigure(1, weight=1, minsize=100)
frame.grid_rowconfigure(2, weight=0)
frame.grid_rowconfigure(3, weight=0)
frame.grid_rowconfigure(4, weight=0)
frame.grid_rowconfigure(5, weight=4)

def onconfigure_button(self, event):
menu = self.options["menu"]
maxw = self.font.measure(self.unselected)
print(maxw)
for i in range(menu.index("end") + 1):
label = menu.entrycget(i, "label")
width = self.font.measure(label)
maxw = max(maxw, width)
print(label, width)
#print(label, label.winfo_width())
print("button width: ", self.button.winfo_width())
maxw = max(maxw, self.button.winfo_width())
print(maxw)
# Wrapping both widgets in frames allowed us to sidestep the padding
# added by the OptionMenu "handle". So while the widgets are now the
# same size, the "handle" width is not accounted for in the width
# calculations and may overlap with wide menu entries!
#
# I need a way to get the width of the menu "handle".
self.options_frame.config(width=maxw)
self.button_frame.config(width=maxw)
self.options_frame.config(height=self.options_frame.winfo_height())
self.button_frame.config(height=self.button_frame.winfo_height())
self.options_frame.pack_propagate(False)
self.button_frame.pack_propagate(False)
event.widget.unbind("")
return

# Question
# When I maximize the window, four events are generated, and I
# see the images scaled-up in a slow-motion animation. I try to cancel or
# skip older events, but each new waits till after the resize
# is complete... This suggests that the resize then affects the widget
# size, leading the callback to be called in a loop... but the showsize()
# callback shows that resizing the image does not change the widget size.
#
# Changing the resize to not preserve aspect ratio makes the problem much
# worse. Clearly the change in height is forcing the geometry manager to
# re-evaluate the layout. How do I prevent this?
def onconfigure_image(self, event, image):
print()
widget = event.widget
print("onconfigure for: ", widget)
#if widget.resize_i is not None:
# print("cancelling previous resize: ", widget.resize_id)
# widget.after_cancel(widget.resize_id)
#widget.resize_id = widget.after_idle(self.resize_image, event, image)
widget.resize_id = widget.after(1, self.resize_image, event, image)
widget.resize_count += 1
print("scheduling resize with id: ", widget.resize_id)

def showsize(self, widget):
print()
print("showsize for: ", widget)
print("widget size: ", widget.winfo_width(), widget.winfo_height())

def resize_image(self, event, image):
widget = event.widget
widget.resize_count -= 1
print()
if widget.resize_count > 0:
print(f"{widget.resize_count} events remaining, skipping resize")
return
print("widget size: ", widget.winfo_width(), widget.winfo_height())
print("resize_image for: ", widget)
print("resize id, resize count: ", (widget.resize_id, widget.resize_count))
widget.resize_id = None
#image = image.copy()
#image.thumbnail\
image = image.resize\
( (event.width, event.height)
, resample=PIL.Image.Resampling.BILINEAR
, reducing_gap=None
)
image = PIL.ImageTk.PhotoImage(image)
widget.config(image=image)
# Images are not referenced by tkinter
widget.image = image
#widget.unbind("")
widget.after(1, self.showsize, widget)

def main():
root = tk.Tk()
root.title("Helpful Title")

app = App(root)

root.mainloop()

if __name__ == "__main__":
main()

Изменить: эта версия устраняет первую проблему (и удаляет обратный вызов с помощью req версии winfo_width() и т. д.) ), но я все еще имею дело со вторым моментом — штормом обратных вызовов.
#!/usr/bin/env python3

import math

import tkinter as tk
import tkinter.font
import tkinter.scrolledtext

import PIL.Image
import PIL.ImageTk

class App:
options = ["short", "really really really long"]
unselected = ""

def __init__(self, parent, **kwargs):
title = parent.winfo_toplevel().title()
font = tk.font.Font(family="Arial", size=12, weight="bold")

# Create a frame for the entire window
frame = tk.Frame(parent, **kwargs)
frame.pack(fill=tk.BOTH, expand=True)

# Set the title label from the window title
title_label = tk.Label(frame, text=title, font=font)
title_label.grid(row=0, columnspan=2, padx=10, pady=10)

# Load the logos
logo1_image = PIL.Image.new("RGB", (200,200), (0,255,0))
logo2_image = PIL.Image.new("RGB", (200,200), (255,0,0))

logo1_label = tk.Label(frame, bg="orange", borderwidth=0, pady=0)
logo2_label = tk.Label(frame, bg="blue", borderwidth=0, pady=0)

logo1_label.resize_count = 0
logo2_label.resize_count = 0
logo1_label.resize_id = None
logo2_label.resize_id = None
print("logo1_label: ", logo1_label)
print("logo2_label: ", logo2_label)

# TODO:
# I'm seeing slow-motion resize on large resizes. I believe that
# multiple resizes are being queued, but I can't cancel the queue. I
# need to make this callback schedule a cancellable callback that then
# resizes.
logo1_label.bind\
("", lambda e, i=logo1_image: self.onconfigure_image(e, i))
logo2_label.bind\
("", lambda e, i=logo2_image: self.onconfigure_image(e, i))

logo1_label.grid(row=1, column=0, padx=0, pady=0, sticky="nsew")
logo2_label.grid(row=1, column=1, padx=0, pady=0, sticky="nsew")

# Label for cell (2,0)
c00_label = tk.Label\
(frame, font=font, text="cell (2,0)")
c00_label.grid(row=2, column=0, padx=10, pady=10, sticky="ew")

# Create the OptionMenu
options_var = tk.StringVar()
options_var.set(self.unselected)

options_frame = tk.Frame(frame, bg="red")

options = tk.OptionMenu(options_frame, options_var, *self.options)
options.configure(font=font, anchor="c")
options["menu"].configure(font=font)

options.pack(fill=tk.BOTH, expand=True)
options_frame.grid(row=2, column=1, padx=10, pady=10)

# Create the Button
button_frame = tk.Frame(frame, bg="red")

button = tk.Button\
(button_frame, font=font, text="implement option", anchor="c")
button.pack(fill=tk.BOTH, expand=True)
button_frame.grid(row=3, column=1, padx=10, pady=(0,0))

# not sure why I can't get the font from the widget, ie:
# font = tk.font.nametofont(self.options.cget("font"))
# *** _tkinter.TclError: named font font1 does not already exist
self.font = font
self.options_frame = options_frame
self.button_frame = button_frame
self.options = options
self.button = button

#parent.bind("", self.onconfigure_button)
self.onconfigure_button(None)

# Create the labels for the 4th row
c30_label = tk.Label\
(frame, font=font, text="cell (4,0)")
c30_label.grid(row=4, column=0, padx=10, pady=10, sticky="ew")

c31_label = tk.Label\
(frame, font=font, text="cell (4,1)")
c31_label.grid(row=4, column=1, padx=10, pady=10, sticky="ew")

text = tk.scrolledtext.ScrolledText\
(frame, state=tk.DISABLED, font=font)
text.grid(row=5, columnspan=2, padx=10, pady=10, sticky="nsew")

frame.grid_columnconfigure(0, weight=1, minsize=100, uniform="column")
frame.grid_columnconfigure(1, weight=1, minsize=100, uniform="column")
frame.grid_rowconfigure(0, weight=0)
frame.grid_rowconfigure(1, weight=1, minsize=100)
frame.grid_rowconfigure(2, weight=0)
frame.grid_rowconfigure(3, weight=0)
frame.grid_rowconfigure(4, weight=0)
frame.grid_rowconfigure(5, weight=4)

def onconfigure_button(self, event):
menu = self.options["menu"]
maxw = self.font.measure(self.unselected)
for i in range(menu.index("end") + 1):
label = menu.entrycget(i, "label")
width = self.font.measure(label)
maxw = max(maxw, width)
maxw = maxw / self.font.measure("0")
maxw = math.ceil(maxw)

# Allow the widget to request its optimal width.
self.options.configure(width=maxw)

maxw = max(self.button.winfo_reqwidth(), self.options.winfo_reqwidth())

self.options_frame.config(width=maxw)
self.button_frame.config(width=maxw)

#print()
#print("button frame act height: ", self.button_frame.winfo_height())
#print("option frame act height: ", self.options_frame.winfo_height())
#print("button frame req height: ", self.button_frame.winfo_reqheight())
#print("option frame req height: ", self.options_frame.winfo_reqheight())

#print("button act height: ", self.button.winfo_height())
#print("option act height: ", self.options.winfo_height())
#print("button req height: ", self.button.winfo_reqheight())
#print("option req height: ", self.options.winfo_reqheight())

self.options_frame.config(height=self.options.winfo_reqheight())
self.button_frame.config(height=self.button.winfo_reqheight())
self.options_frame.pack_propagate(False)
self.button_frame.pack_propagate(False)
#event.widget.unbind("")

# Question
# When I maximize the window, four events are generated, and I
# see the images scaled-up in a slow-motion animation. I try to cancel or
# skip older events, but each new waits till after the resize
# is complete... This suggests that the resize then affects the widget
# size, leading the callback to be called in a loop... but the showsize()
# callback shows that resizing the image does not change the widget size.
#
# Changing the resize to not preserve aspect ratio makes the problem much
# worse. Clearly the change in height is forcing the geometry manager to
# re-evaluate the layout. How do I prevent this?
def onconfigure_image(self, event, image):
print()
widget = event.widget
print("onconfigure for: ", widget)
#if widget.resize_i is not None:
# print("cancelling previous resize: ", widget.resize_id)
# widget.after_cancel(widget.resize_id)
#widget.resize_id = widget.after_idle(self.resize_image, event, image)
widget.resize_id = widget.after(1, self.resize_image, event, image)
widget.resize_count += 1
print("scheduling resize with id: ", widget.resize_id)

def showsize(self, widget):
print()
print("showsize for: ", widget)
print("widget size: ", widget.winfo_width(), widget.winfo_height())

def resize_image(self, event, image):
widget = event.widget
widget.resize_count -= 1
print()
if widget.resize_count > 0:
print(f"{widget.resize_count} events remaining, skipping resize")
return
print("widget size: ", widget.winfo_width(), widget.winfo_height())
print("resize_image for: ", widget)
print("resize id, resize count: ", (widget.resize_id, widget.resize_count))
widget.resize_id = None
#image = image.copy()
#image.thumbnail\
image = image.resize\
( (event.width, event.height)
, resample=PIL.Image.Resampling.BILINEAR
, reducing_gap=None
)
image = PIL.ImageTk.PhotoImage(image)
widget.config(image=image)
# Images are not referenced by tkinter
widget.image = image
#widget.unbind("")
widget.after(1, self.showsize, widget)

def main():
root = tk.Tk()
root.title("Helpful Title")

app = App(root)

root.mainloop()

if __name__ == "__main__":
main()

Изменить: я предполагал, что менеджер геометрической сетки будет поддерживать строгое соотношение между строками в соответствии с определенными весами. Таким образом, учитывая веса 1:4, изменение размера окна сохранит соотношение между строками 1:4. Однако менеджер геометрии также учитывает запросы размеров своих дочерних элементов. Если размер окна увеличивается и дочерний виджет запрашивает использование нового пространства, то менеджер геометрии увеличит вес этого дочернего элемента, вызывая новое событие изменения размера. Это происходит до предела, при котором ребенок больше не может потреблять пространство. Этот эффект возникает даже между разными (возможно, несмежными) менеджерами сетки, которые делят пространство.
Изучая события, я не обнаружил никакой разницы между событиями изменения размера окна и событиями изменения размера сетки. TKinter, похоже, не помечает источник событий, поэтому невозможно просто отфильтровать события изменения размера сетки. Я также не смог найти способа предотвратить запуск дочерних запросов размера для событий изменения размера сетки. Я думал, что отключение распространения может сработать, но нет...
Единственное решение - затем связать дочернее изменение размера с событиями, происходящими выше по иерархии, такими как корневое окно, которое будет неявно фильтровать события изменения размера сетки. К сожалению, это оставляет пробел, поскольку менеджер сетки затем выделяет больше места для дочернего элемента, поэтому, вероятно, лучше переместить затронутых дочерних элементов к другому менеджеру. Можно моделировать размер сетки с помощью некоторого нелинейного соотношения между размером окна и размером изображения.
Изменить: то, что я написал, применимо не только к сетке, а к любому менеджеру геометрии, который расширяется в дополнительное доступное пространство, например, Pack с помощьюExpand=True.

Тем не менее, вместо разделения В моей существующей сетке я решил попытаться установить вес этой строки равным нулю (отключить расширение) и вручную изменить размер ячеек при изменении внешнего фрейма... но это хороший способ аварийно завершить работу tkinter:
def frame_configure_resize_grid_cell(self, event, image, widget):
gridframe = event.widget
if not gridframe.height:
gridframe.height = event.height
return
print("frame old height, frame new height", gridframe.height, event.height)
aspect = event.height / gridframe.height
gridframe.height = event.height
old_height = widget.winfo_height()
#_,_,_,old_height = frame.grid_bbox(1,0)
new_height = round(old_height * aspect)
print("old height, aspect, new height: ", old_height, aspect, new_height)
widget.config(height=new_height)


Подробнее здесь: https://stackoverflow.com/questions/790 ... containers
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Соответствие OptionMenu и ширины кнопки
    Anonymous » » в форуме Python
    0 Ответы
    17 Просмотры
    Последнее сообщение Anonymous
  • Соответствие OptionMenu и ширины кнопки
    Anonymous » » в форуме Python
    0 Ответы
    17 Просмотры
    Последнее сообщение Anonymous
  • Соответствие OptionMenu и ширины кнопки
    Anonymous » » в форуме Python
    0 Ответы
    23 Просмотры
    Последнее сообщение Anonymous
  • Соответствие OptionMenu и ширины кнопки
    Anonymous » » в форуме Python
    0 Ответы
    19 Просмотры
    Последнее сообщение Anonymous
  • Предотвращение обрезки изображений flexbox с изменяемым размером границами окна или окна браузера.
    Гость » » в форуме CSS
    0 Ответы
    42 Просмотры
    Последнее сообщение Гость

Вернуться в «Python»