PySide/PyQt: PointingHandCursor recipes? - python

I have a pyside application with a numerous buttons, toolbuttons, tabs etc... I would like all of them to have a 'pointing hand' cursor when hovering/clicking. This means my code is full of statements like this:
someWidget.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
It is a relatively long, ugly line.
I can encapsulate the above in a function:
def hand_cursor(widget):
widget.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
This makes the rest of the code somewhat neater:
hand_cursor(someWidget)
But I still have to write that line all over the place.
Does anyone know of a recipe/trick to be able to get all my buttons, tab bars etc to have the pointing hand cursor without repeating myself all over?

I would maintain a list of all the widgets for which you want this behaviour, and loop:
widgetsToChange = [someWidget, anotherWidget, ...]
for w in widgetsToChange:
hand_cursor(w)
#or w.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
You can also use QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) to change for all the application.

Related

Adding Tkinter Buttons to a list without .append

I'm currently having a play around with tkinter trying to make my code efficient. I want to be able to index my buttons at a later date so I'm trying to put then into a list without first creating a blank list and appending them to it as I loop (The only way I currently know how to do it). I've got the below currently going on but at the moment every time the loop runs it overwrites my button at index 0 rather than appending to the list, how would I go about using something like this or use list comprehension to create my buttons?
for btn in range (6):
self.Preset_Lbl = [tk.Button(self.window, width = 5, height = 1, text = mylist[0]
[btn], relief = "groove")]
self.Preset_Lbl[btn].grid(row = btn, column = 1)
thanks in advance
trying to make my code efficient
In general, you should only bother to optimize code after it has been proven (by measurements, i.e. through profiling) that it is a major bottleneck. In general for a GUI the creation of a window and filling it with widgets is a one-time event. So it is unlikely to be the most inefficient code in the program.
First, optimizations can often make code more complicated and difficult to read and understand. For example, for the programmer stopbutton is pretty much self explanatory. If you referred to the same object as buttons[0] it would not be clear what that button is supposed to do.
Second, you don't know what the bottlenecks in your code are before you measure them.
For example, in my stl2pov program, it turned out that string formatting was actually consuming most of the time. And using the appropriate type specifier to the format string halved the necessary time.
Another example is where replacing statistics.mean with statistics.fmean reduced the runtime by about a third.
In contrast to the comments, you can indeed create a list variable and initialize all its values in the same line as such without needing to loop through it (It does use a for loop inside the implementation, but it's reduced to one line and without using the function append() directly):
self.Preset_lbl = [tk.Button(self.window, width=5, height=1, text=mylist[0][btn], relief="groove") for btn in range(6)]
You need to decide for yourself, if you care about the readability of this approach or you can also check if it would impact performance in any way by profiling/benchmarking it like stated by Roland Smith.

Python: implement a "software-wide" setting that does not change often without running an if statement in every loop

I want Python to kind of ignore a statement that is unlikely to be called in a function that is often called.
I do not have a formal education in programming, so please excuse my lackluster ability to desribe things. I will try to explain the concept by example.
Say I am writing a video game, first-person shooter, drawing 60 frames per second.
In the settings menu, the user can select whether or not to display the name of other players above their head. If they disable this, I store this value as showplayernames = False.
Then in my drawing function that outputs the graphics I have:
def draw():
#code that draws the graphics on screen
if showplayernames:
#code that draws the name of players on screen
I call this function 60 times a second, but there is absolutely no point for checking if showplayernames is True 60 times a second. It will not change that often, in fact I could make this a kind of "constant" during play by preventing it to change. If showplayernames is False, then the third and fourth lines of the code are completely redundant, but they are executed nevertheless. The computer isn't smart enough to know it can ignore it, and there is a performance difference: reading a value and then checking if it is false takes time.
I could write two copies of the game (or at least the draw() function), one with only the first two lines when the user selects not to show names in the settings, and another without the if statement, and then run the appropriate one.
def draw_with_names():
#code that draws the graphics on screen
#code that draws the name of players on screen
def draw_without_names():
#code that draws the graphics on screen
Although looping through either of these 60 times a second is more efficient than running draw() ,this is obviously not the way to go. There are dozens of settings like this.
So how do software and game designers implement these kind of "software-wide" settings efficiently?
I'm not a game developer, but here's one option. Create a list of function pointers and add or remove from the list based on settings. Example:
def draw_player_names():
# Code to overlay names
def draw_fps():
# Code to overlay fps
def draw():
# Main code to draw a frame of the game
# Hold all the functions to call
optional_funcs = []
if showplayernames: optional_funcs.append(draw_player_names)
if show_fps: optional_funcs.append(draw_fps)
# Main game loop
while True:
draw()
for f in optional_funcs: f()
This can be extended for any number of functions/options.
not an game designer, but here is my voice.
You could store settings inside json file next to you python, but then you need to cover reading, getting right values etc.
You could use Environment variables to store value but that would end up using still "if" in the code.
Game designers use triggers and events to get things done, and on the lowest level I would assume those things also use if's.
system-wide-settings will in the end be used with if's
You could use overwrites based on event/trigger and use "same" draw function in both times but that only complicates code, and we all know to "keep it simple".
Sorry if this is not the answer you were looking for.
As Matthias said, you shouldn't really bother about this kind of optimization. Look at these two very silly functions:
def lot_of_ifs(settings):
#do something
a=2**10
b=2**10
c=2**10
for setting in settings:
if setting:
#do something more
a=2**10
b=2**10
c=2**10
def no_ifs():
#do something
a=2**10
b=2**10
c=2**10
timeit("lot_of_ifs([0,0,0,0,0])", globals=globals())
0.2630380000000514
timeit("no_ifs()", globals=globals())
0.10232830000040849
The cost of creating a list, looping over it, and executing five ifs is about 0.16 seconds for one million iterations, or 160 nanoseconds per iteration, while at 60 fps you have 16.6 million nanoseconds to execute your code.

Issue with differentiating between two of the same items in a tkinter menu

The program I created allows for any letter on the keyboard the user types to be written on the turtle graphics canvas. In my program, I have also created a Python menu to which a Point object (for each letter function) is written to every time a user executes a function/draws a letter. However, because of the nature of my program, the user can also attach two of the same functions to the menu. If two of the same things get attached to the menu, for example two functions, I need a way to differentiate between them somehow. To do this, I have created a counter in another function and called that counter function in the function where the menu is written to, like so:
Counter function:
def increase():
if not hasattr(increase, "counter"):
increase.counter = 0
increase.counter += 1
Code block when menu is written to:
global loki
kli.config(state = NORMAL)
loki = ("{}".format(po.getfunction()))
increase() #<-- Counter function
undo1.add_command(label = str(increase.counter) + Point.__str__(po), command = lambda: selectundo(undo1.index(po)))
Point.__str__ is this method in the Point class:
def __str__(self):
return "({})".format(self.function)
However, I keep getting this error whenever I select something from the menu:
undo1.add_command(label = str(increase.counter) + Point.__str__(po), command = lambda: selectundo(undo1.index(po)))
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/tkinter/__init__.py", line 2782, in index
i = self.tk.call(self._w, 'index', index)
tkinter.TclError: bad menu entry index "(<function draw_O at 0x105834d90>)"
I am thinking it has something to do with the following function, which undoes the function that is selected from the menu, but I am not sure:
def selectundo(x):
# This function undoes the function selected from the menu
for ty in range(x, len(function)):
undoHandler()
update()
listen()
Although, before I concatenated str(increase.counter) to Point.__str__(po), it worked perfectly.
So, what am I doing wrong here? Any help at all is much appreciated! :)
EDIT: Just to clear up what I am trying to do and why, I am trying to differentiate between two (or more) of the same functions if they are written to the menu and I am doing this because of the selectundo function (shown above) since, for example, if the user draws two (or more) of the same letter, I need to be able to differentiate between them, because right now, when I can't, the selectundo function undoes ALL instances of that letter, NOT just the first instance of what is pressed on the menu, which is what I actually want the program to do. If what I am trying to do to accomplish the task is not possible or if there is a better way to accomplish the task, please tell be about any/the other way that I can use to accomplish the task. I hope this helps alleviate any confusion! :)

"Inception" situation with wxPython

The title is amusing , I know. Its like movie "Inception" situation .Dream in a dream in a dream .
Hi everyone ,I am using wxpython to make an app.
I want to achieve something like this .(This is just idea of the problem)
func1(self,event):
some widgets added
func2
func2(self,event):
remove previous widgets (by using event.GetEventObject().GetParent().Hide())
add new ones
func3
func3(self,event):
remove widgets added in func2
recall widgets added in func1 (event.GetEventObject().GetParent().Show())
I have traversed too much inside , like 3 times jumping from functions to other nested
functions that i have no track of event .
If i store the ids of events (in a list) with
event.GetId()
while traversing in every function , is there a way if i can use those ids to
replace
event.GetEventObject().GetParent().Show()
event.GetEventObject().GetParent().Hide()
with
id1.GetEventObject().GetParent().Hide()
id2.GetEventObject().GetParent().Show()
I just want to know this kind of thing is possible ?
Or theres a better simpler way ?
If any still is in such trouble , I found some ways...
First of all , you don't need to use IDs for this.....Much simpler way is
create different panels........
When you want to hide one , you can simply do
panelname.Hide()
When you want to show another ,
panelname.Show() # Or this also works (event.GetEventObject().GetParent().Show()\Hide())
Note : 1) Remember to give all widgets (buttons etc) individual IDs (or -1 will do).
2) You can also create your overlapping panels with a function call too.(example - After a button is clicked).
3) Also you can create a common panel ( a parent panel ) and then create child panels and in the init body . And then you can simply hide and show these panels in a function binded (may be with a button etc) .
I solved my problem like this . Did'nt need to use GetId() . But there might be others ways. So do share if you have some other idea.I hope this helps someone someday...Thank you all.

Getting visible text from a QTextEdit in PyQt

This is related to another question I found here that seems to be inactive for a few months, so I think it's worth asking again.
I have created a simple QDialog that has a QTextEdit and a QPushButton. This pops up in my application when a user right-clicks and selects the option to "add comments". I want them to be able to write free-form text and I'll just save whatever they write as a long string with no concern for new lines, etc.
When the user clicks the button, it executes code like this:
self.connect(accept_button,QtCore.SIGNAL('clicked()'),lambda arg=str(view_textedit.toPlainText()): self.updateGroupComments(arg))
def updateGroupComments(self,new_comment_str):
print "Updating user comment to have new string: " + new_comment_str
self.group_entry.list_of_user_comments[self.currentFrameCounter] = new_comment_str
This is not detecting the TextEdit text that is visible (it only detects whatever the text edit text is set to when it is created). How do I make a simple command that returns the currently visible text from a QTextEdit. Again, the function
toPlainText()
is not working correctly... it doesn't find the currently visible text, only whatever text was on screen before changes or additions started being made by the user.
If this can't be done without subclassing and appealing to cursor positions, it makes the whole thing seem worthless... so please keep suggestions only to those implemented without subclassing or manipulating cursors. It should be really simple and straightforward to just return all currently visible text... what am I missing?
Objects that are being bound to default arguments are evaluated at the definition time. The function is working correctly, it returns whatever was in the text field when it was executed. Your code simply calls it at the wrong moment. If you want to use lambda, then do:
self.connect(
accept_button, QtCore.SIGNAL('clicked()'),
lambda: self.updateGroupComments(str(view_textedit.toPlainText()))
)
Or make view_textedit an instance attribute instead, and do simply
self.connect(
accept_button, QtCore.SIGNAL('clicked()'), self.updateGroupComments
)
And change updateGroupComments to call self.view_textedit.toPlainText instead of taking an argument.
BTW, this is not PyQt specific, this is how Python works in general.
To illustrate my last comment, that lambda can very well be replaced with:
def slot():
self.updateGroupComments(str(view_textedit.toPlainText()))
self.connect(accept_button, QtCore.SIGNAL('clicked()'), slot)

Categories