How to detect the reselection of same pyqt combobox element - python

I have a pyqtgraph Combobox which is defined as follows.
def __init__(self):
# some other stuff....
mylist=OrderedDict()
mylist['1k'] = 1
mylist['10k'] = 10
mylist['100k'] = 100
mylist['1M'] = 1000
self.myselectorA = ComboBox()
self.myselectorA.setItems(mylist)
self.myselectorA.currentIndexChanged.connect(self.selchangedA)
def selchangedA(self):
self.sq.setA(self.myselectorA.value())
if self.sq.gainlink:
self.sq.setB(100./self.myselectorA.value())
self.viewupdate = True
self.myselectorB.setValue(100./self.myselectorA.value())
self.viewupdate = False
The attached callback function selchangedA does some stuff which includes the optional update of a second Combobox (myselectorB). This update is dependant on a further variable gainlink.
I have the situation where I need to be able to detect the reselection of the same element in the combobox so that it updates the secondary combobox. Is this possible?
I understand that the user should just select the appropriate value on the secondary combobox but I want maximum flexibility for the user.

Instead of currentIndexChanged(int) you can connect the signal activated(int) (which is also emitted if the choice didn't change but an element was selected) to selchangedA(self, int). Besides that you can save the current index of the combo box in a separate variable and check in selchangedA if the value is the same as the previous and act accordingly.

Related

can you change the stacking order of a window using its id?

I'm trying to make a procedure that updates the stacking order of randomly created windows based on their y value (so that things that are closer to the top of the screen display under things that are lower down).
Basically I have a button that creates a window by calling a class statement. Each time a window is created, its id and y value get put in an array, which would get sorted and looped through to update the stacking order.
I figured having the id of each window that is created would be enough to change the variables of specific windows, using the id of the window.lift(), but it looks like you can't point to an object with its id like that. If I'm not mistaken I can't just use the class name because I don't want to change the whole class, just the specific window.
Anybody know what I can use instead of the id to get this to work? Is it just impossible the way I have it planned?
Here's my code in case it's helpful, unfinished because obviously it doesn't work:
import tkinter as tk
import random
# creates a new window
def makewndw(event):
a = testwindow()
# create main window - click to create a new window
mainwindow = tk.Tk()
mainwindow.bind('<Button-1>', makewndw)
# this sorts the windows
class stacker():
stackerwindow = tk.Toplevel()
yarray = [{'ident': 0, 'ypos': 0}]
def arupdate(self):
#sort array by ypos
self.yarray.sort(key=lambda x: x.get('ypos'))
# print(self.yarray)
# get length of array
arlen = len(self.yarray)
# loop through array between pos 1 and end
for x in range(1,arlen):
# extract dictionary from that position
tempex = self.yarray[x]
# populate temp list with values from tempex
templist = []
for i in tempex.values():
templist.append(i)
# get just the id
tempid = templist[0]
# use id to update stacking order
tempid.lift()
# ^^^ this is where i'm suck because clearly this isn't working
self.stackerwindow.after(10, self.arupdate)
class testwindow():
def __init__(self):
# create a window
self.window = tk.Toplevel()
self.y = random.randrange(100, 500)
self.window.geometry('200x200+800+{y}'.format(y=str(self.y)))
# give info to sorter
self.infdict = {'ident': id(self.window), 'ypos': self.y}
stacker.yarray.append(self.infdict)
st = stacker()
st.arupdate()
mainwindow.mainloop()
I'm a beginner so I'm sorry if the answer here is obvious, and sorry about how messy I'm sure my code is.

How to find and change DataViewListCtrl BackgroundColour of Selected text in WxPython?

My problem is I can't find the command to change the background color of DataViewListCtrl for selected text/row/item in DataViewListCtrl object.
I looked into the documentation but there's no apparent reference.
https://docs.wxpython.org/wx.dataview.DataViewCtrl.html#wx-dataview-dataviewctrl
I'm using the sample_one.py script from this reference:
https://wiki.wxpython.org/How%20to%20add%20a%20menu%20bar%20in%20the%20title%20bar%20%28Phoenix%29
The DataViewListCtrl has this example code:
self.dvlc = dv.DataViewListCtrl(
self,
style=dv.DV_MULTIPLE
| dv.DV_ROW_LINES
| dv.DV_HORIZ_RULES
| dv.DV_VERT_RULES,
)
self.dvlc.SetBackgroundColour("#ffffff")
self.dvlc.SetForegroundColour("black")
What I'm looking to do is similar to Tkinter example below (change the selected text background color to blue):
style.configure(
"Treeview", background="#FFFFDD", foreground="black", fieldbackground="#FFFFDD"
)
style.map("Treeview", background=[("selected", "#F0FFFF")])
I haven't been able to try a workaround yet as I'm not sure how to get the needed command/value, but on my end the selected DataViewListCtrl items have a #242424 color (I checked with an eyedropper from a screenshot).
I found the 2 parameters IsSelected and IsRowSelected in the doc:
https://docs.wxpython.org/wx.dataview.DataViewListCtrl.html#wx.dataview.DataViewListCtrl.IsRowSelected
https://docs.wxpython.org/wx.dataview.DataViewCtrl.html#wx.dataview.DataViewCtrl.IsSelected
and tested as
self.dvlc = dv.DataViewListCtrl(
self,
style=dv.DV_MULTIPLE
| dv.DV_ROW_LINES
| dv.DV_HORIZ_RULES
| dv.DV_VERT_RULES,
)
# Give it some columns.
self.dvlc.AppendTextColumn("Id", width=40)
self.dvlc.AppendTextColumn("Artist", width=170)
self.dvlc.AppendTextColumn("Title", width=260)
self.dvlc.AppendTextColumn("Genre", width=80)
# Load the data. Each item (row) is added as a sequence
# of values whose order matches the columns.
for itemvalues in musicdata:
self.dvlc.AppendItem(itemvalues)
# — 1st test with same result as 2nd below
# if self.dvlc.IsSelected == True:
# self.dvlc.SetBackgroundColour("#0066ff")
# else:
# self.dvlc.SetBackgroundColour("#F0FFFF")
if self.dvlc.IsRowSelected == True:
self.dvlc.SetBackgroundColour("#0066ff")
else:
self.dvlc.SetBackgroundColour("#F0FFFF")
self.dvlc.SetForegroundColour("black")
I tried also without the == True explicit as
# — 1st test with same result as 2nd below
# if self.dvlc.IsSelected:
# self.dvlc.SetBackgroundColour("#0066ff")
# else:
# self.dvlc.SetBackgroundColour("#F0FFFF")
if self.dvlc.IsRowSelected:
self.dvlc.SetBackgroundColour("#0066ff")
else:
self.dvlc.SetBackgroundColour("#F0FFFF")
and the unexpected blue background displays by default (when not selected).
Is there some documented "selected" parameter or otherwise known working method to be able to capture the selected background color and change it in WxPython?
You will have to use a custom renderer if you want to change the way the selected items background is rendered -- and you will have to overwrite the entire background entirely, as the default one will still be drawn, you will just be able to paint over it.
Alternatively, you can define a custom wxRendererNative-derived object and override its DrawItemSelectionRect() method and then set it as the renderer to use globally. This should be simpler, but it will change selection drawing in all controls using this function.

Pyside2 build several buttons and memory

I have built a application which contained multi QComboBox.
On change, each one add buttons (about 100) in a grid layout, here a part of the called function:
for x in xrange(1,100):
my_list_shots.append(str(x))
x=2 # line 1 has the menu
y=1 # row
incrementLineX=1 # every 10 we go to line 2 (x+1) and reset incrementLine and y (row) to 1
for i in xrange(1,121):
try:
my_shot_number=my_list_shots[i]
my_shot_number = "%03d"%int(my_shot_number)
self.buttons = QtWidgets.QPushButton(my_shot_number,self)
self.buttons.setStyleSheet("background-color:brown;color:white")
self.buttons.clicked.connect(partial(self.my_open_mov,my_shot_number))
self.my_grid_layout.addWidget(self.buttons,x,y,1,1)
except Exception as e:
self.buttons = QtWidgets.QPushButton("",self)
self.buttons.setEnabled(False)
my_shot_number=""
y=y+1
incrementLineX=incrementLineX+1
if incrementLineX>10:
x=x+1
y=1
incrementLineX = 1
self.buttons.clicked.connect(partial(self.my_open_mov,my_shot_number))
and so on...
I worried about the memory, if I keep my window open all day long with many changes, I'll create each time 99 buttons? or not..?
How can I properly build my buttons?
Do I need to destroy them when I call the function?
In another way, what I want is to replace new buttons by old ones and I don't want to create thousand of buttons if I keep the windows open.
I just need the way to do it.
I have got the solution.
I use deleteLater() for each created buttons before to rebuild new ones.
# DELETE THE OLD WIDGET IN THE LAYOUT GRID
def clearShotsWidget(self):
while self.shotsWidgetLayout.count():
item = self.shotsWidgetLayout.takeAt(0)
item.widget().deleteLater()
self.shotsWidgetLayout.removeItem(item)
The other idea is to put all the build buttons in a list and delete them before to create the new ones.
Thanks a lot
Gui

How to add Combobox every time when i press button in Tkinter?

I wanna build GUI and there is a button which Combobox adds every time the button is pressed. but i cant find out how to figure or code this concept
And, is there any other Widget? or is there other way to build my concept??
please some one help me..
the main concept without using tkinter is Like this shown . i want this concept to be made in Tkinter.
[THIS IS WHAT I TRIED BUT WHENEVER I PRESS THE BUTTON, ALL COMBOBOX ADDED WORKS TOGETHER (which means when i change the list name, all combobox also changes..)]
def Plus_EXT():
button_plus = Button(window3,justify = CENTER,command = Add_EXT, text= "+")
button_plus.grid(row=0,column=0)
def Add_EXT():
global Num
window3.update()
Num += 1
CEList1 = [x for x in os.listdir(cur_dir) if ('CE' in x.upper()) and ('.rpt' in x)]
RPT_EXT_file=ttk.Combobox(window3, values=CEList1,textvariable= EXT_String)
RPT_EXT_file.grid(row=8+Num,column=1)
RPT_EXT_file.set("FILE")
[MAIN CONCEPT WITHOUT USING TKINTER]
CE_Num= int(input("How Many EXTRA Chordae?: "))
User_File = input("Type the New File Name: ")
for Num_Of_EXT in range(CE_Num):
RPT_EXT_file = input("Type the RPT of EXTRA CHORDAE: ") + ".rpt"
EXTRA(User_File,RPT_EXT_file,Num_Of_EXT)
EXTRA_PLT(User_File,Num_Of_EXT)
the output i want is { everytime i press the button a new Combobox is added in the frame with the lists which works separately.}
The issue is that all your Combobox widgets are linked with same textvariable called EXT_String.So when you change the value of one Combobox widget, it updates same value in all of them.
I would suggest to keep a list of such variables and index that list using NUM in your loop to assign the textvariable.
UPDATE:
Just an example based on limited code shared in Add_EXT method:
global var_list
var_list.append(IntVar()) #Or StringVar(), whatever you are using
RPT_EXT_file=ttk.Combobox(window3, values=CEList1,textvariable=var_list[-1])

Tkinter radio button clear / reset values

I am writing a Tkinter program for the first time and have a question on radio buttons. What I am trying to do is this:
open a set of images (one at a time).
When an image is opened, annotate a value using the radio button.
Collect this value in a list
So, in this example I have 2 compounds and the list would have 2 annotations.
The problem I have is, if by mistake the user clicks radiobutton 2 instead of one, and then corrects him/herself, the list will have 4 items (3 for the first image, 1 for the second). How do I handle this, so that the list will have only 2 values?
import Tkinter as tk
from PIL import ImageTk, Image
from tkFileDialog import askopenfilename
cmp_list = ["VU435DR","VU684DR"]
li = []
li_final = []
def sel():
selection = str(var.get())
if selection == "1":
li.append("Antagonist")
elif selection == "2":
li.append("Agonist")
for i in range(len(cmp_list)):
root = tk.Tk()
var = tk.IntVar()
ig = str(cmp_list[i] + '.png')
img = ImageTk.PhotoImage(Image.open(ig))
panel = tk.Label(root,image=img)
panel.pack(side = "top",fill="none",expand="no")
#w = tk.Text(height=2,width=50)
#w.pack(side='right")
q = tk.Radiobutton(root,text="Antagonist",command=sel,value=1,variable=var)
q.pack()
r = tk.Radiobutton(root,text="Agonist",command=sel,value=2,variable=var)
r.pack()
root.mainloop()
print li
Your code is creating more than one instance of tk.Tk(). This is not how Tkinter was designed to work, and it will yield unpredictable behavior. A proper Tkinter program always has exactly one instance of tk.Tk().
If you need more than one window, for the second and subsequent windows you should create an instance of tk.Toplevel.
To answer your specific question about how to handle someone first hitting one radiobutton and then the other -- the problem is that you are unconditionally appending to your list each time they click on a radiobutton. The solution is to use some sort of flag or indicator to know whether one of the radiobuttons has been clicked, or change your code so that it doesn't matter.
Let's look at that second option - make it so it doesn't matter. When you open up a new image you can automatically append a value to your list. In this case, set it to None to say that nothing has been picked yet. Then, in sel, you would always replace the last element rather than append a new element, since you know that the last element always refers to the current compound.

Categories

Resources