I'm creating a simple GUI app using Tkinter with Python, but I'm having problems adding a scrollbar to a single frame. The frame is visible from top to bottom on my 20" but in order to display everything on a netbook or any other low res screen it needs a scrollbar. Here's a snippet of how I thought it would work (it does with listboxes).
framelist = Tkinter.Frame(self.pmaster, relief=FLAT, borderwidth=0)
framelist.pack(fill=BOTH, padx=0, pady=0)
yscroll = Tkinter.Scrollbar(framelist, width=10, orient=VERTICAL)
yscroll.pack(fill=Y,side=RIGHT,padx=0,pady=0)
Though this doesn't work with frames apparently. Any help on this issue from you guys will be deeply appreciated!
I'm also wondering if Tkinter might be outdated. It was the only GUI interface I learned in school, but thats several years ago and it doesn't really meet my demands anymore. Surely there must be a better alternative? I'm on Ubuntu btw.
The frame widget of tkinter doesn't scroll. One solution is to put your whole frame in a canvas (as a canvas object), and attach the scrollbar to the canvas. You have to tell the canvas how big the scrollable area is, which you can do by getting the size of the frame once you've placed all the widgets in it. Though, you might want to reconsider your UI design -- scrollable frames aren't very easy to use no matter what GUI toolkit you use.
As for whether Tkinter is outdated... some say yes, some say no. There is a lot of tkinter misinformation out there so take all tkinter opinions with a grain of salt (even mine!). Tkinter continues to improve, it hasn't stagnated. If you have the luxury of using python 2.7 or greater you have access to the ttk widgets which offer platform-specific themes and additional widgets such as a notebook and hierarchical tree among others.
For alternatives you might want to check out wxPython. In my experience it seems to have considerably more bugs and quirks than tkinter, but has a lot more widgets and seems to be more popular.
I like to think that the difference between tkinter and wxPython is like the difference between Home Depot (a home improvement / lumbar yard store) and Ikea (prefabricated furniture that you assemble yourself) - one gives you all the bits and pieces to make just about anything you want (tkinter) the other gives you a lot of pre-packaged stuff. Each approach has its strengths and weaknesses.
Related
GUI noob here. I've created a simple screen overlay where the user can click-drag to create a transparent rectangle.
Think 'cropping an image'.
That part was easy enough. The problem is that I want to reset the overlay if/when the user attempts to click-drag inside the transparent rectangle, thereby starting a new rectangle.
Illustrative example code:
import tkinter as tk
def fail_click(evt):
print(evt.x)
root = tk.Tk()
root.attributes('-topmost', True)
root.attributes('-transparentcolor', 'grey')
canvas = tk.Canvas(root, width=300, height=300, bg='grey')
canvas.bind('<Button-1>', fail_click)
canvas.pack()
root.mainloop()
What I expected:
An invisible canvas upon which I could draw.
What I got:
An empty frame I could reach through to grab whatever is on the other side. This surprised me because I was unaware that 'transparent' == 'not there'. While I can imagine cool things to do with this newfound knowledge, in this case, it's the opposite of what I want.
The question(s):
Is this the intended behavior for GUI windows in general or is this a quirk of Tkinter? In other words, could I solve this problem simply by using a different toolkit, e.g., wxPython or pyQt?
Assuming this is the intended behavior, is there a workaround for getting my invisible canvas to register mouse events. e.g., capturing the click event and redirecting it to where it belongs (the canvas)? It doesn't need to be trivial, I just need a signpost pointing me in the right direction.
Notes:
I haven't put a lot of effort into this as it's just a silly side project I'm working on. I just decided to ask the question before I waste time I don't have trying a hundred different things, like learning how to use a new toolkit. And, who knows, maybe it'll help save someone else some time.
I've glanced over the code from this answer - https://stackoverflow.com/a/42880450/3602761 - but that's just capturing click events. I need the whole caboodle: Motion, Button-1, B1-Motion, ButtonRelease-1, etc.
I'm only using Python and Tkinter here because Python is the language I'm most familiar with and Tkinter is built-in. Feel free to offer suggestions straying from this implementation decision.
If you want partially transparent write the number as you wish instead of 0 in alpha
import tkinter as tk
def fail_click(evt):
print(evt.x)
root = tk.Tk()
root.attributes('-topmost', True)
root.attributes('-alpha', 0)
canvas = tk.Canvas(root, width=300, height=300, bg='grey')
canvas.bind('<Button-1>', fail_click)
canvas.pack()
root.mainloop()
Suppose one were to want to build a spread-sheet in tkinter. So one could have (many) cells, most of which would take text entry, but some could be drop-down lists (tkinter comboboxes) etc.
Is that feasible in tkinter for a spreadsheet of any size? (Say 100x10)? Or would that many tkinter Text object and comboboxes etc just be too much handle performance wise? (Or is there some other way to do this other than just gridding many tkinter objects?)
I ask not because I want to do this literally, but because I need to build an app in which users are presented with lots of chunks of information, any of them editable. It's convenient for the user to access those chunks directly (click on the cell) rather than have to pass through some preliminary interface.
I think the best way to know is to try. I used the code below to create a 100x10 grid of Entry widgets and tkinter did not seem slow once all widgets were created. But it will depend on the performances of the computer.
import tkinter as tk
root = tk.Tk()
for i in range(100):
for j in range(10):
tk.Entry(root)).grid(row=i, column=j)
root.mainloop()
Is there a bug in the natural scrollbar trough click event handler, is something wrong with the way I set it up, or something else? I ask because it doesn't always work (when it doesn't work, it either does nothing or else moves to the wrong position). The scrollbars otherwise work fine. Sometimes the trough clicks do work, but a lot of the time they don't. (More than one or two clicks is often needed to discover the problem.)
hbar=Scrollbar(newTabFrame, orient=HORIZONTAL, bg=self.d["hbgcolor"], troughcolor=self.d["htcolor"]);
vbar=Scrollbar(newTabFrame, orient=VERTICAL, bg=self.d["vbgcolor"], troughcolor=self.d["vtcolor"]);
scroll=Text(self, newTabFrame, font=self.d["font"], undo=True, tabs=("0.4c"), wrap=self.d["wrap"], xscrollcommand=hbar.set, yscrollcommand=vbar.set, bg=self.d["bgcolor"], fg=self.d["fgcolor"], insertbackground=self.d["insertcolor"]);
vbar.grid(row=1, column=2, columnspan=2, rowspan=4, sticky=N+S);
vbar.config(command=scroll.yview);
hbar.grid(sticky=E+W);
hbar.config(command=scroll.xview);
Once again, it's only when I click on the troughs where I experience a problem. All the other scrollbar functionality (which is most of it) works fine. For those who don't know, a scrollbar trough is the long part of the scrollbar that does not move.
My scrollbars are attached to Text widgets inside Frames that are inside of ttk.Notebook widget tabs.
To directly answer your question, no, there is no known bug in the scrollbar code. This code has been in use for more than a decade without anyone reporting issues with the trough. That doesn't mean a bug isn't possible, but it is highly unlikely. There also doesn't appear to be any problems with how you defined the scrollbar or how you attached it to the text widget. .
Based on comments to the original question, it sounds like you have some bindings in your app that may be interfering with the default behavior of the scrollbar.
I want to make a whole column of various widgets scrollable in a Tkinter GUI, like so:
Tkinter can only attach scrollbars to certain widgets, of which, frames are not included. Making a scollable column is a common practice in interfaces, and there should be a simple solution, but so far, all I have been able to find is this hacky example of a scrollable frame, using a canvas widget. A similar hacky solution was used in a similar stack overflow question.
Is there a commonly accepted way in Tkinter to make a column, or a group of widgets, that is scrollable?
The solution using the canvas is the commonly accepted way to solve this problem. It's really not all that hacky, and the end result can be indistinguishable from having a native scrolling container widget.
If you're making a single column, another option is to use a text widget, and use the widget's ability to embed other widgets. Insert a widget, then insert a newline, insert another widget, etc. You then get the scrolling ability for free. The only thing you need to worry about is configuring the width of the embedded windows, which isn't too hard to do.
I'm working on a project using Tkinter and Python. In order to have native theming and to take advantage of the new widgets I'm using ttk in Python 2.6. My problem is how to allow the user to scroll through the tabs in the notebook widget (a la firefox). Plus, I need a part in the right edge of the tabs for a close button. The frame for the active tab would need to fill the available horizontal space (including under the scroll arrows).
I thought I could do this using the Place geometry manager, but I was wondering if there was a better way? The ttk python docs don't have any methods to deal with this that I could see.
Edit: looks like there are difficulties for even trying to implement this using place. For one, I'd still need the tabs to scroll and the active panel to stay in the one place.
The notebook widget doesn't do scrolling of tabs (or multiple layers of them either) because the developer doesn't believe that they make for a good GUI. I can see his point; such GUIs tend to suck. The best workaround I've seen is to have a panel on the side that allows the selection of which pane to display. You can then apply tricks to that panel to manage the amount of information there (e.g., by making it a treeview widget and holding the info hierarchically, much like most email clients handle mail folders; treeview widgets are scrollable).
I've never used these widgets so I have no idea how possible this is, but what I would try is something akin to the grid_remove() method. If you can move the tabs to an invisible widget, or just make them invisible without losing content, that's what I'd look for/try.