I don't have a lot of GUI programming experience and very little in Tkinter, so bear with me. It seems to me that the Tkinter menu interface is seriously wrong. I'm referring in particular to the way menu entries are addressed.
Menu entries are not widgets. add_command - or, for that matter, any add - does not return an object which we can use to address the entry. In order to
reconfigure
delete
insert relative to
an entry, an index must be provided. The index is, usually, just an index in the current list of entries in the menu. That means, all entries that exist (after additions and deletions) at the present time in the index.
It seems logical to organize the code in a GUI around groups of functions that are related from a user's point of view. Say, Undo and Redo should be together in the Edit menu. But the Edit menu may also contain other groups of functions - Cut, Copy, Paste, or perhaps Find. It makes sense to put the code that handles Undo and Redo in one module, the code for Cut, Copy and Paste in another, the code for Find in yet another. These modules are unrelated to each other, except for the fact that they all exist in the Edit menu. However, just because of that fact, it seems that in Tkinter menus they need to know if a module "above" inserts or deletes an entry in its own "area", because that affects the indices of their own entries. Isn't that quite fragile? Or am I missing something?
Related
I have a program I'm developing using PyQt5 where I have 6 QComboBoxes to make selections from, and then based on these selections you can narrow down the data further. For clarity, it looks like this:
Image of Program
If something is in the "weakness" category I want the user to have the option to remove it from the final selection process in case the initial results are too narrow.
Here's where the problem is:
The final calculation is based on what checkboxes are checked. To make sure this is as reflected in the GUI I do the following things whenever a combobox is changed:
Changed the QStackedWidgets to the "deactivated" label
Determine strengths and weaknesses based on type data from comboboxes
Unchecked all the checkboxes and mark the appropriate ones as checked.
Code for this is below:
#deactivate all stacks
for t in range(0,18):
str_type0 = self.value[t].lower()[0:3]
str_stack0 = 'self.str_'+str(str_type0)
eval(str_stack0).setCurrentIndex(0)
weak_type0 = self.value[t].lower()[0:3]
weak_stack0 = 'self.weak_'+str(weak_type0)
eval(weak_stack0).setCurrentIndex(0)
#strong loop
for t in range(0,len(self.r)):
str_type = self.value[self.r[t]].lower()[0:3]
str_stack = 'self.str_'+str(str_type)
eval(str_stack).setCurrentIndex(1)
#weak loop
for t in range(0,len(self.q)):
weak_type = self.value[self.q[t]].lower()[0:3]
weak_stack = 'self.weak_'+str(weak_type)
eval(weak_stack).setCurrentIndex(1)
#set all checkboxes as checked if currently shown in stack
for t in range(0,18):
checkstr0= self.value[t].lower()[0:3]
checkstr1='self.weak_'+str(checkstr0)+'_act'
eval(checkstr1).setChecked(False)
weak_stack1 = 'self.weak_'+str(checkstr0)
weak_stack1 = eval(weak_stack1)
if weak_stack1.currentIndex() == 1:
eval(checkstr1).setChecked(True)
else: continue
This is fine and works even if it's a little clunky (goal is tomake it work and then make it work efficiently later). The issue is that changing a checkbox is what triggers the function that does all the calculating for the results, but since multiple checkboxes change at the same time, or even just changing one, triggers this function a multiplicity of times. It's a huge waste of computation.
I've thought of some solutions. I think perhaps the best way to solve this problem is to run the function not when any particular checkbox changes but there is a change. Something like:
if any (checkbox.checkState()==changed): do something.
I'm not sure if that would be a good solution, or how to even do that.
Any ideas are appreciated. Thanks in advance!
Figured out the answer while I continued to think about the problem. The problem was that it signaled every time it changed, which is a horrible amount while the program configured itself.
The obvious yet simple solution was to change the checkboxes from:
checkbox.stateChanged.connect(function)
to
checkbox.pressed.connect(function)
This way the checkbox signal will only go forth when I physically press on it in the program. Hopefully this will be able to help anyone else out there who runs into the same issue in the future.
I have been implementing in a drop down menu (offically called a "Tkinter.OptionMenu") inside my application, that once clicked open will allow users to skip to certain parts of the form (like skipping to a certain chapter of a book/play). I want to be able to OPEN that drop down menu on an event i.e with code however as much as i have searched, it seems the very best i can do i to do a .focus_set() which is better than nothing, but all it does it place a faint outline around the widget. I would like it to fully open it up, just as if the user had clicked on it.
I'm pretty sure that i'm missing something simple, but help would be appreciated :)
Edit: Yes, i do have good reason to programatically open it, and even if i didn't it would still be nice to find out. I do not need access to the functions the list gives, but rather, i need the user to pick something from that drop down, and so i would like to open it for them
So I'm teaching myself Python/Pygame, and to start off I'm trying to make a basic menu that the user can scroll through and then select an item to go to a different menu. My initial thought was to define the menus as a tuple of menu items, with each item being a tuple of what text to display and where selecting that item leads you. So, for example:
mainmenu = (("Go to Menu 1",menu1),("Go to Menu 2",menu2))
menu1 = (("Go to Menu 2",menu2),("Return to Main Menu",mainmenu))
menu2 = (("Go to Menu 1",menu1),("Return to Main Menu",mainmenu))
then have a function like makeMenu(menu) that prints out a given menu, and allows the user to scroll through it. When the user makes their selection, makeMenu(menu) is called again, this time being passed the menu that corresponds to the currently selected option.
The problem is that Python won't allow you to define mainmenu in terms of other menus that haven't been defined yet. This makes sense, but I can't think of a way to create a series of interconnected menus without defining them relative to each other. I'm sure there's a simple solution, but for the life of me I can't figure it out. Any thoughts?
Often, for menus, I like to use the State Pattern. A fully fledged one may be overkill for your current needs - but it should lead you in the right direction. An example of this for C, specifically talking about game states, is available on gamedevgeek.com.
This may not directly answer your questions, but it should lead you to a much more extensible and robust solution.
I have a program displaying a gtk Treeview with 5-6 columns and a great number of rows, therefore there is a scrollbar on the side.
I would like to ensure that if you quit the program and restart it, the position and sort order that was in the last state before closing is loaded up again.
So:
how do I store the selected item position in the treeview?
how do I store the sorted order ?
and how do I bring them back when displaying the treeview again, so that it would display the list just like it was when closing the program ?
I have seen some answers on SO on how to store the selected item position but not how to display it again in the same way.
I'd appreciate if you have any tips on how to do that.
I'm afraid I'm answering in C rather than Python as that's what I'm familiar with. You should be able to translate the function names easily enough. You can get and retrieve the selected row with gtk_tree_view_get_cursor and gtk_tree_view_set_cursor If you store the path it should be the same when you reload the data. You can use gtk_tree_view_get_columns and g_list_find to find which column is selected. Setting the cursor will scroll the window so it is visible. This will restore the view to roughly what it was when saved. If you want to be more precise try looking at gtk_scrollable_get_vadjustment and gtk_scrollable_get_hadjustment To store the sort order you can use gtk_tree_sortable_get_sort_column_id and set it with gtk_tree_sortable_set_sort_column_id
I hope that gets you started, it's well worth spending some time familiarising yourself with the tree view documentation.I t can be a bit overwhelming at first but it is worth the effort in the long run.
How would i go about setting up a Tkinter Text widget to do something similar to IDLE's entry? For example:
>>> Entry goes here!
However, i know how to insert them at the beginning of each line, but how would i go about making it non deletable, so that you cannot delete the >>>? I have searched around on google about this, but to no avail.
If the solution only has to be "Good Enough", the technique I would use is this:
When you insert the prompt, remember the index of the end of the prompt.
Add a binding to the widget for the events you care about (eg: <BackSpace> and <Delete> and <<Cut>>)
In this binding you can look at the index of the insertion cursor and selection, and if it's prior to the saved index, ignore the event (ie: do a return "break").
This should work more-or-less OK, though it allows you to insert characters prior to the prompt. Rewriting all the bindings that alter a text widget is a fairly daunting task, but just tracking deletes isn't too hard.
To solve the problem perfectly would require you write a little tcl code to intercept the low level insert and delete commands of the actual widget. It's possible, though it requires a decent understanding of the underlying tcl code. For an example, see this answer: https://stackoverflow.com/a/11180132/7432