因此,经过数小时或阅读文章并查看tkinter的文档后,我发现在Windows机器上,tkinter滚动条的颜色选项将无法使用,因为滚动条直接从Windows获取其主题。我的问题是默认主题的颜色确实与我的程序冲突,因此我试图找到一种不涉及导入其他GUI程序包(例如PyQt)的解决方案(我无法在工作中访问pip,所以这是一个问题以获取新软件包)
除了使用单独的程序包之外,任何人都可以向我介绍一些有关如何编写自己的侧边栏以滚动文本小部件的文档。到目前为止,我所发现的甚至与我想做的事情都差不多的一个答案是这个问题。(使用ttk样式更改tkinter中滚动条的外观)
从我可以看到的示例来看,只是更改了滚动条的背景,因此我仍然无法使用该示例。我在用于配置样式的行之一上出现错误。
style.configure("My.Horizontal.TScrollbar", *style.configure("Horizontal.TScrollbar"))
TypeError: configure() argument after * must be an iterable, not NoneType
不知道该如何处理该错误,因为我只是在遵循用户示例,因此我不确定它为什么对他们有用,但对我却不起作用。
到目前为止,我尝试过的是:
我如何创建文本框以及与之配套的滚动条。
root.text = Text(root, undo = True)
root.text.grid(row = 0, column = 1, columnspan = 1, rowspan = 1, padx =(5,5), pady =(5,5), sticky = W+E+N+S)
root.text.config(bg = pyFrameColor, fg = "white", font=('times', 16))
root.text.config(wrap=NONE)
vScrollBar = tkinter.Scrollbar(root, command=root.text.yview)
hScrollBar = tkinter.Scrollbar(root, orient = HORIZONTAL, command=root.text.xview)
vScrollBar.grid(row = 0, column = 2, columnspan = 1, rowspan = 1, padx =1, pady =1, sticky = E+N+S)
hScrollBar.grid(row = 1 , column = 1, columnspan = 1, rowspan = 1, padx =1, pady =1, sticky = S+W+E)
root.text['yscrollcommand'] = vScrollBar.set
root.text['xscrollcommand'] = hScrollBar.set
按照此处的文档在Windows机器上,我的以下尝试似乎无济于事。正如我在其他文章中所读到的,这与滚动条从Windows本地获取其主题有关。
vScrollBar.config(bg = mainBGcolor)
vScrollBar['activebackground'] = mainBGcolor
hScrollBar.config(bg = mainBGcolor)
hScrollBar['activebackground'] = mainBGcolor
我想这可以归结为:
是否可以创建我自己的侧边栏(可以根据主题更改颜色)而无需导入其他python包?如果是这样,我应该从哪里开始,或者有人可以将我链接到文档,因为我的搜索总是会把我带回到Tkinter滚动条信息。由于这些config()选项适用于Linux,因此它们不适用于Windows。
不是一个完整的答案,但是您是否考虑过创建类似自己的滚动条:
import tkinter as tk
class MyScrollbar(tk.Canvas):
def __init__(self, master, *args, **kwargs):
if 'width' not in kwargs:
kwargs['width'] = 10
if 'bd' not in kwargs:
kwargs['bd'] = 0
if 'highlightthickness' not in kwargs:
kwargs['highlightthickness'] = 0
self.command = kwargs.pop('command')
tk.Canvas.__init__(self, master, *args, **kwargs)
self.elements = { 'button-1':None,
'button-2':None,
'trough':None,
'thumb':None}
self._oldwidth = 0
self._oldheight = 0
self._sb_start = 0
self._sb_end = 1
self.bind('<Configure>', self._resize)
self.tag_bind('button-1', '<Button-1>', self._button_1)
self.tag_bind('button-2', '<Button-1>', self._button_2)
self.tag_bind('trough', '<Button-1>', self._trough)
self._track = False
self.tag_bind('thumb', '<ButtonPress-1>', self._thumb_press)
self.tag_bind('thumb', '<ButtonRelease-1>', self._thumb_release)
self.tag_bind('thumb', '<Leave>', self._thumb_release)
self.tag_bind('thumb', '<Motion>', self._thumb_track)
def _sort_kwargs(self, kwargs):
for key in kwargs:
if key in ['buttontype', 'buttoncolor', 'troughcolor', 'thumbcolor', 'thumbtype']:
self._scroll_kwargs[key] = kwargs.pop(key) # add to custom dict and remove from canvas dict
return kwargs
def _resize(self, event):
width = self.winfo_width()
height = self.winfo_height()
# print("canvas: (%s, %s)" % (width, height))
if self.elements['button-1']: # exists
if self._oldwidth != width:
self.delete(self.elements['button-1'])
self.elements['button-1'] = None
else:
pass
if not self.elements['button-1']: # create
self.elements['button-1'] = self.create_oval((0,0,width, width), fill='#006cd9', outline='#006cd9', tag='button-1')
if self.elements['button-2']: # exists
coords = self.coords(self.elements['button-2'])
if self._oldwidth != width:
self.delete(self.elements['button-2'])
self.elements['button-2'] = None
elif self._oldheight != height:
self.move(self.elements['button-2'], 0, height-coords[3])
else:
pass
if not self.elements['button-2']: # create
self.elements['button-2'] = self.create_oval((0,height-width,width, height), fill='#006cd9', outline='#006cd9', tag='button-2')
if self.elements['trough']: # exists
coords = self.coords(self.elements['trough'])
if (self._oldwidth != width) or (self._oldheight != height):
self.delete(self.elements['trough'])
self.elements['trough'] = None
else:
pass
if not self.elements['trough']: # create
self.elements['trough'] = self.create_rectangle((0,int(width/2),width, height-int(width/2)), fill='#00468c', outline='#00468c', tag='trough')
self.set(self._sb_start, self._sb_end) # hacky way to redraw thumb
self.tag_raise('thumb') # ensure thumb always on top of trough
self._oldwidth = width
self._oldheight = height
def _button_1(self, event):
self.command('scroll', -1, 'pages')
return 'break'
def _button_2(self, event):
self.command('scroll', 1, 'pages')
return 'break'
def _trough(self, event):
width = self.winfo_width()
height = self.winfo_height()
size = (self._sb_end - self._sb_start) / 1
thumbrange = height - width
thumbsize = int(thumbrange * size)
thumboffset = int(thumbrange * self._sb_start) + int(width/2)
thumbpos = int(thumbrange * size / 2) + thumboffset
if event.y < thumbpos:
self.command('scroll', -1, 'pages')
elif event.y > thumbpos:
self.command('scroll', 1, 'pages')
return 'break'
def _thumb_press(self, event):
print("thumb press: (%s, %s)" % (event.x, event.y))
self._track = True
def _thumb_release(self, event):
print("thumb release: (%s, %s)" % (event.x, event.y))
self._track = False
def _thumb_track(self, event):
if self._track:
# print("*"*30)
print("thumb: (%s, %s)" % (event.x, event.y))
width = self.winfo_width()
height = self.winfo_height()
# print("window size: (%s, %s)" % (width, height))
size = (self._sb_end - self._sb_start) / 1
# print('size: %s' % size)
thumbrange = height - width
# print('thumbrange: %s' % thumbrange)
thumbsize = int(thumbrange * size)
# print('thumbsize: %s' % thumbsize)
clickrange = thumbrange - thumbsize
# print('clickrange: %s' % clickrange)
thumboffset = int(thumbrange * self._sb_start) + int(width/2)
# print('thumboffset: %s' % thumboffset)
thumbpos = int(thumbrange * size / 2) + thumboffset
# print("mouse point: %s" % event.y)
# print("thumbpos: %s" % thumbpos)
point = (event.y - (width/2) - (thumbsize/2)) / clickrange
# point = (event.y - (width / 2)) / (thumbrange - thumbsize)
# print(event.y - (width/2))
# print(point)
if point < 0:
point = 0
elif point > 1:
point = 1
# print(point)
self.command('moveto', point)
return 'break'
def set(self, *args):
oldsize = (self._sb_end - self._sb_start) / 1
self._sb_start = float(args[0])
self._sb_end = float(args[1])
size = (self._sb_end - self._sb_start) / 1
width = self.winfo_width()
height = self.winfo_height()
if oldsize != size:
self.delete(self.elements['thumb'])
self.elements['thumb'] = None
thumbrange = height - width
thumbsize = int(thumbrange * size)
thumboffset = int(thumbrange * self._sb_start) + int(width/2)
if not self.elements['thumb']: # create
self.elements['thumb'] = self.create_rectangle((0, thumboffset,width, thumbsize+thumboffset), fill='#4ca6ff', outline='#4ca6ff', tag='thumb')
else: # move
coords = self.coords(self.elements['thumb'])
if (thumboffset != coords[1]):
self.move(self.elements['thumb'], 0, thumboffset-coords[1])
return 'break'
if __name__ == '__main__':
root = tk.Tk()
lb = tk.Listbox(root)
lb.pack(side='left', fill='both', expand=True)
for num in range(0,100):
lb.insert('end', str(num))
sb = MyScrollbar(root, width=50, command=lb.yview)
sb.pack(side='right', fill='both', expand=True)
lb.configure(yscrollcommand=sb.set)
root.mainloop()
我已经留下我的评论了,为了我一生,我似乎无法单击并拖动拇指以使其正常工作,但是它具有以下功能的简单滚动条:
我已经修改了拇指代码,以修复单击和拖动滚动:
import tkinter as tk
class MyScrollbar(tk.Canvas):
def __init__(self, master, *args, **kwargs):
self._scroll_kwargs = { 'command':None,
'orient':'vertical',
'buttontype':'round',
'buttoncolor':'#006cd9',
'troughcolor':'#00468c',
'thumbtype':'rectangle',
'thumbcolor':'#4ca6ff',
}
kwargs = self._sort_kwargs(kwargs)
if self._scroll_kwargs['orient'] == 'vertical':
if 'width' not in kwargs:
kwargs['width'] = 10
elif self._scroll_kwargs['orient'] == 'horizontal':
if 'height' not in kwargs:
kwargs['height'] = 10
else:
raise ValueError
if 'bd' not in kwargs:
kwargs['bd'] = 0
if 'highlightthickness' not in kwargs:
kwargs['highlightthickness'] = 0
tk.Canvas.__init__(self, master, *args, **kwargs)
self.elements = { 'button-1':None,
'button-2':None,
'trough':None,
'thumb':None}
self._oldwidth = 0
self._oldheight = 0
self._sb_start = 0
self._sb_end = 1
self.bind('<Configure>', self._resize)
self.tag_bind('button-1', '<Button-1>', self._button_1)
self.tag_bind('button-2', '<Button-1>', self._button_2)
self.tag_bind('trough', '<Button-1>', self._trough)
self._track = False
self.tag_bind('thumb', '<ButtonPress-1>', self._thumb_press)
self.bind('<ButtonRelease-1>', self._thumb_release)
# self.bind('<Leave>', self._thumb_release)
self.bind('<Motion>', self._thumb_track)
def _sort_kwargs(self, kwargs):
to_remove = []
for key in kwargs:
if key in [ 'buttontype', 'buttoncolor', 'buttonoutline',
'troughcolor', 'troughoutline',
'thumbcolor', 'thumbtype', 'thumboutline',
'command', 'orient']:
self._scroll_kwargs[key] = kwargs[key] # add to custom dict
to_remove.append(key)
for key in to_remove:
del kwargs[key]
return kwargs
def _get_colour(self, element):
if element in self._scroll_kwargs: # if element exists in settings
return self._scroll_kwargs[element]
if element.endswith('outline'): # if element is outline and wasn't in settings
return self._scroll_kwargs[element.replace('outline', 'color')] # fetch default for main element
def _width(self):
return self.winfo_width() - 2 # return width minus 2 pixes to ensure fit in canvas
def _height(self):
return self.winfo_height() - 2 # return height minus 2 pixes to ensure fit in canvas
def _resize(self, event):
width = self._width()
height = self._height()
if self.elements['button-1']: # exists
# delete element if vertical scrollbar and width changed
# or if horizontal and height changed, signals button needs to change
if (((self._oldwidth != width) and (self._scroll_kwargs['orient'] == 'vertical')) or
((self._oldheight != height) and (self._scroll_kwargs['orient'] == 'horizontal'))):
self.delete(self.elements['button-1'])
self.elements['button-1'] = None
if not self.elements['button-1']: # create
size = width if (self._scroll_kwargs['orient'] == 'vertical') else height
rect = (0,0,size, size)
fill = self._get_colour('buttoncolor')
outline = self._get_colour('buttonoutline')
if (self._scroll_kwargs['buttontype'] == 'round'):
self.elements['button-1'] = self.create_oval(rect, fill=fill, outline=outline, tag='button-1')
elif (self._scroll_kwargs['buttontype'] == 'square'):
self.elements['button-1'] = self.create_rectangle(rect, fill=fill, outline=outline, tag='button-1')
if self.elements['button-2']: # exists
coords = self.coords(self.elements['button-2'])
# delete element if vertical scrollbar and width changed
# or if horizontal and height changed, signals button needs to change
if (((self._oldwidth != width) and (self._scroll_kwargs['orient'] == 'vertical')) or
((self._oldheight != height) and (self._scroll_kwargs['orient'] == 'horizontal'))):
self.delete(self.elements['button-2'])
self.elements['button-2'] = None
# if vertical scrollbar and height changed button needs to move
elif ((self._oldheight != height) and (self._scroll_kwargs['orient'] == 'vertical')):
self.move(self.elements['button-2'], 0, height-coords[3])
# if horizontal scrollbar and width changed button needs to move
elif ((self._oldwidth != width) and (self._scroll_kwargs['orient'] == 'horizontal')):
self.move(self.elements['button-2'], width-coords[2], 0)
if not self.elements['button-2']: # create
if (self._scroll_kwargs['orient'] == 'vertical'):
rect = (0,height-width,width, height)
elif (self._scroll_kwargs['orient'] == 'horizontal'):
rect = (width-height,0,width, height)
fill = self._get_colour('buttoncolor')
outline = self._get_colour('buttonoutline')
if (self._scroll_kwargs['buttontype'] == 'round'):
self.elements['button-2'] = self.create_oval(rect, fill=fill, outline=outline, tag='button-2')
elif (self._scroll_kwargs['buttontype'] == 'square'):
self.elements['button-2'] = self.create_rectangle(rect, fill=fill, outline=outline, tag='button-2')
if self.elements['trough']: # exists
coords = self.coords(self.elements['trough'])
# delete element whenever width or height changes
if (self._oldwidth != width) or (self._oldheight != height):
self.delete(self.elements['trough'])
self.elements['trough'] = None
if not self.elements['trough']: # create
if (self._scroll_kwargs['orient'] == 'vertical'):
rect = (0, int(width/2), width, height-int(width/2))
elif (self._scroll_kwargs['orient'] == 'horizontal'):
rect = (int(height/2), 0, width-int(height/2), height)
fill = self._get_colour('troughcolor')
outline = self._get_colour('troughoutline')
self.elements['trough'] = self.create_rectangle(rect, fill=fill, outline=outline, tag='trough')
self.set(self._sb_start, self._sb_end) # hacky way to redraw thumb without moving it
self.tag_raise('thumb') # ensure thumb always on top of trough
self._oldwidth = width
self._oldheight = height
def _button_1(self, event):
command = self._scroll_kwargs['command']
if command:
command('scroll', -1, 'pages')
return 'break'
def _button_2(self, event):
command = self._scroll_kwargs['command']
if command:
command('scroll', 1, 'pages')
return 'break'
def _trough(self, event):
# print('trough: (%s, %s)' % (event.x, event.y))
width = self._width()
height = self._height()
coords = self.coords(self.elements['trough'])
if (self._scroll_kwargs['orient'] == 'vertical'):
trough_size = coords[3] - coords[1]
elif (self._scroll_kwargs['orient'] == 'horizontal'):
trough_size = coords[2] - coords[0]
# print('trough size: %s' % trough_size)
size = (self._sb_end - self._sb_start) / 1
if (self._scroll_kwargs['orient'] == 'vertical'):
thumbrange = height - width
elif (self._scroll_kwargs['orient'] == 'horizontal'):
thumbrange = width - height
thumbsize = int(thumbrange * size)
if (self._scroll_kwargs['orient'] == 'vertical'):
thumboffset = int(thumbrange * self._sb_start) + int(width/2)
elif (self._scroll_kwargs['orient'] == 'horizontal'):
thumboffset = int(thumbrange * self._sb_start) + int(height/2)
thumbpos = int(thumbrange * size / 2) + thumboffset
command = self._scroll_kwargs['command']
if command:
if (((self._scroll_kwargs['orient'] == 'vertical') and (event.y < thumbpos)) or
((self._scroll_kwargs['orient'] == 'horizontal') and (event.x < thumbpos))):
command('scroll', -1, 'pages')
elif (((self._scroll_kwargs['orient'] == 'vertical') and (event.y > thumbpos)) or
((self._scroll_kwargs['orient'] == 'horizontal') and (event.x > thumbpos))):
command('scroll', 1, 'pages')
return 'break'
def _thumb_press(self, event):
self._track = True
def _thumb_release(self, event):
self._track = False
def _thumb_track(self, event):
# print('track')
if self._track:
width = self._width()
height = self._height()
# print("window size: (%s, %s)" % (width, height))
size = (self._sb_end - self._sb_start) / 1
coords = self.coords(self.elements['trough'])
# print('trough coords: %s' % coords)
if (self._scroll_kwargs['orient'] == 'vertical'):
trough_size = coords[3] - coords[1]
thumbrange = height - width
elif (self._scroll_kwargs['orient'] == 'horizontal'):
trough_size = coords[2] - coords[0]
thumbrange = width - height
# print('trough size: %s' % trough_size)
thumbsize = int(thumbrange * size)
if (self._scroll_kwargs['orient'] == 'vertical'):
pos = max(min(trough_size, event.y - coords[1] - (thumbsize/2)), 0)
elif (self._scroll_kwargs['orient'] == 'horizontal'):
pos = max(min(trough_size, event.x - coords[0] - (thumbsize/2)), 0)
# print('pos: %s' % pos)
point = pos / trough_size
# print('point: %s' % point)
command = self._scroll_kwargs['command']
if command:
command('moveto', point)
return 'break'
def set(self, *args):
# print('set: %s' % str(args))
oldsize = (self._sb_end - self._sb_start) / 1
self._sb_start = float(args[0])
self._sb_end = float(args[1])
size = (self._sb_end - self._sb_start) / 1
width = self._width()
height = self._height()
if oldsize != size:
self.delete(self.elements['thumb'])
self.elements['thumb'] = None
if (self._scroll_kwargs['orient'] == 'vertical'):
thumbrange = height - width
thumboffset = int(thumbrange * self._sb_start) + int(width/2)
elif (self._scroll_kwargs['orient'] == 'horizontal'):
thumbrange = width - height
thumboffset = int(thumbrange * self._sb_start) + int(height/2)
thumbsize = int(thumbrange * size)
if not self.elements['thumb']: # create
if (self._scroll_kwargs['orient'] == 'vertical'):
rect = (0, thumboffset,width, thumbsize+thumboffset)
elif (self._scroll_kwargs['orient'] == 'horizontal'):
rect = (thumboffset, 0, thumbsize+thumboffset, height)
fill = self._get_colour('thumbcolor')
outline = self._get_colour('thumboutline')
if (self._scroll_kwargs['thumbtype'] == 'round'):
self.elements['thumb'] = self.create_oval(rect, fill=fill, outline=outline, tag='thumb')
elif (self._scroll_kwargs['thumbtype'] == 'rectangle'):
self.elements['thumb'] = self.create_rectangle(rect, fill=fill, outline=outline, tag='thumb')
else: # move
coords = self.coords(self.elements['thumb'])
if (self._scroll_kwargs['orient'] == 'vertical'):
if (thumboffset != coords[1]):
self.move(self.elements['thumb'], 0, thumboffset-coords[1])
elif (self._scroll_kwargs['orient'] == 'horizontal'):
if (thumboffset != coords[1]):
self.move(self.elements['thumb'], thumboffset-coords[0], 0)
return 'break'
if __name__ == '__main__':
root = tk.Tk()
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_rowconfigure(3, weight=1)
root.grid_columnconfigure(3, weight=1)
lb = tk.Listbox(root)
lb.grid(column=1, row=1, sticky="nesw")
for num in range(0,100):
lb.insert('end', str(num)*100)
sby1 = MyScrollbar(root, width=50, command=lb.yview)
sby1.grid(column=2, row=1, sticky="nesw")
sby2 = MyScrollbar(root, width=50, command=lb.yview, buttontype='square', thumbtype='round')
sby2.grid(column=4, row=1, sticky="nesw")
sbx1 = MyScrollbar(root, height=50, command=lb.xview, orient='horizontal', buttoncolor='red', thumbcolor='orange', troughcolor='green')
sbx1.grid(column=1, row=2, sticky="nesw")
sbx2 = MyScrollbar(root, height=50, command=lb.xview, orient='horizontal', thumbtype='round')
sbx2.grid(column=1, row=4, sticky="nesw")
def x_set(*args):
sbx1.set(*args)
sbx2.set(*args)
def y_set(*args):
sby1.set(*args)
sby2.set(*args)
lb.configure(yscrollcommand=y_set, xscrollcommand=x_set)
root.mainloop()
因此,我已经修复了计算方法,以计算出新滚动位置的位置,并将其从用于track和release事件的thumb标签上的绑定更改为整个画布上的绑定,因此,如果用户快速滚动,该绑定仍放开鼠标时释放。
我已经注释掉了光标离开画布时的绑定,因此该行为更接近于现有的滚动条,但是如果希望鼠标离开小部件时停止滚动,则可以重新启用该行为。
至于创建两个类,上面的修改后的代码使您可以使用orient
关键字,这样就可以删除该类(具有样式更改)来代替默认滚动条,如底部的示例所示。
我的目标是在一个有几个标签的框架中添加一个垂直滚动条。当框架内的标签超过框架的高度时,滚动条应该自动启用。经过搜索,我发现了这个有用的帖子。根据那篇文章,我明白为了实现我想要的,(如果我错了,请纠正我,我是一个初学者)我必须先创建一个框架,然后在框架内创建一个画布,并粘贴滚动条到那个框架。之后,创建另一个框架,并将其作为窗口对象放在画布内。所以,我终于想出了这个: 我这样做对吗?有没有更好/更聪明
我试图理解DOM结构 所以我在正文中添加了 但我不明白为什么滚动条也被染成红色? null null
我无法让x和y滚动条在使用Python的Tkinter中工作,尽管我已经遵循了多个示例: 如何在python 3.4中使用tkinter添加2个滚动条 在tkinter中添加滚动条到一组小部件 如何在tkinter中制作一个合适的双滚动条框架 垂直和水平滚动条上的Tkinter小部件 水平和垂直滚动画布小部件 滚动条会出现,但当窗口小于框架时不会激活。我怎样才能让它工作(见下图)? 下面是产生我的
问题内容: 我的目标是让滚动条位于全屏窗口的右侧,允许用户在各种不同的小部件(例如标签和按钮)中上下滚动。从我在该站点上看到的其他答案中,我得出的结论是,必须将滚动条分配给画布才能使其正常运行,我已经尝试将其包含在代码中,但还没有太多成功。 以下代码显示了到目前为止我已完成的工作的简化版本: 运行此代码时,我面临两个问题: 一种是滚动条处于非活动状态,并且不允许用户向下滚动以查看其余文本。 另一个
问题内容: 我的目标是向具有多个标签的框架添加垂直滚动条。一旦框架内的标签超过框架的高度,滚动条应自动启用。搜索之后,我发现了这个有用的帖子。根据该帖子,我了解到要实现我想要的功能(如果我错了,请纠正我,我是一个初学者),我必须先创建一个,然后在该框架内创建一个并将滚动条粘贴到该框架上好。之后,创建另一个框架并将其作为窗口对象放在画布内。所以,我终于想出了这个: 我做对了吗?有没有更好/更聪明的方
Scrollbar 控件常用于创建一个水平或者垂直的滚动条,通常情况下,Scrollbar 控件可以与 Listbox、Text、Canvas 以及 Entry 等控件一起使。 滚动条控件是 GUI 程序中经常使用的一种控件类型,它主要用来控制控件区域的可见范围,比如当 Text 控件的文本内容非常多时,为了方便用户阅读,可以给 Text 控件增加滚动条,用户只需拖动滚动条就能完成内容的阅读。