I have a window containing multiple QRowWidgets, which are custom widgets defined by me. These QRowWidgets contain QLineEdits and other standard widgets. To show or hide certain parts of a QRowWidget, I overdefined the focusInEvent() methodes of all the widgets within it. It works perfectly, when I click on the QRowWidget, the hidden elements appear.
The weird thing is that the blinking cursor line hovewer doesn't appear in the QLineEdits within the custom widgets. I can select them both by a mouse click or with Tab, and a glow effect indicates that the QLineEdit is selected in it, I can select a text in it, or start typing at any location wherever I clicked, but the cursor never appears and it's quite annoying.
My 1st thought was that it is a bug on Mac, but I have the same experience on SuSe Linux.
I'm using python 2.7 and PyQt4.
This is in the __init__() of the QRowWidget:
for i in self.findChildren(QWidget):
i.focusInEvent = self.focusInEvent
And then this is the own focusInEvent():
def focusInEvent(self, event):
if self.pself.focusedLine:
self.pself.focusedLine.setStyleSheet("color: #666;")
self.pself.focusedLine.desc.hide()
self.pself.focusedLine.closebutton.hide()
self.setStyleSheet("color: #000;")
self.desc.show()
self.closebutton.show()
self.pself.focusedLine = self
I suspect you do not make a call to the original focusInEvent() when you override it. Your function should look something like:
def focusInEvent(self,...):
QParent.focusInEvent(self,...)
# the rest of your code
where QParent is the nearest base class for your widgets is.
Either that, or make sure you call focusInEvent() on your QLineEdit widgets as part of your function.
Given the comments, it sounds like you are dynamically reassigning the focusInEvent function on the insantiatations in your custom widget. I would either make a derived class for each of the widgets you use that just overrides focusInEvent as above, or include a line like
type(self).focusInEvent(self,..)
in you function.
Related
I want to dynamically change the number of sliders on my application window, in dependence of the number of checked items in a QStandardItemModel structure.
My application window has an instance of QVBoxLayout called sliders, which I update when a button is pressed:
first removing all sliders eventually in there:
self.sliders.removeWidget(slider)
And then creating a new set.
The relevant code:
def create_sliders(self):
if len(self.sliders_list):
for sl in self.sliders_list:
self.sliders.removeWidget(sl)
self.sliders_list = []
for index in range(self.model.rowCount()):
if self.model.item(index).checkState():
slid = QSlider(Qt.Horizontal)
self.sliders.addWidget(slid)
self.sliders_list.append(slid)
The principle seems to work, however what happens is weird as the deleted sliders do not really disappear but it is as they were 'disconnected' from the underlying layout.
When created, the sliders keep their position among other elements while I resize the main window.
However, once they've been removed, they occupy a fixed position and can for instance disappear if I reduce the size of the window.
Unfortunately I'm having difficulties in linking images (it says the format is not supported when I try to link from pasteboard), so I hope this description is enough to highlight the issue.
Do I have to remove the sliders using a different procedure?
EDIT
Thanks to #eyllansec for his reply, it condenses a bunch of other replies around the topic, which I wasn't able to find as I did not know the method deleteLater() which is the key to get rid of widgets inside a QLayout.
I am marking it as my chosen (hey, it's the only one and it works, after all!), however I want to propose my own code which also works with minimal changes w.r.t. to what I proposed in the beginning.
The key point here is that I was using the metod QLayout.removeWidget(QWidget) which I was wrongly thinking, it would..er..Remove the widget! But actually what it does is (if I understood it right) remove it from the layout instance.
That is why it was still hanging in my window, although it seemed disconnected
Manual reference
Also, the proposed code is far more general than what I need, as it is a recursion over layout contents, which could in principle be both other QLayout objects or QWidgets (or even Qspacer), and be organized in a hierarchy (i.e., a QWidget QLayout within a QLayout and so on).
check this other answer
From there, the use of recursion and the series of if-then constructs.
My case is much simpler though, as I use this QVLayout instance to just place my QSliders and this will be all. So, for me, I stick to my list for now as I do not like the formalism of QLayout.TakeAt(n) and I don't need it. I was glad that the references I build in a list are absolutely fine to work with.
In the end, this is the slightly changed code that works for me in this case:
def create_sliders(self):
if len(self.sliders_list):
for sl in self.sliders_list:
sl.deleteLater()
self.sliders_list = []
for index in range(self.model.rowCount()):
if self.model.item(index).checkState():
slid = QSlider(Qt.Horizontal)
self.sliders.addWidget(slid)
self.sliders_list.append(slid)
It is not necessary to save the sliders in a list, they can be accessed through the layout where it is contained. I have implemented a function that deletes the elements within a layout. The solution is as follows:
def create_sliders(self):
self.clearLayout(self.sliders)
for index in range(self.model.rowCount()):
if self.model.item(index).checkState():
slid = QSlider(Qt.Horizontal)
self.sliders.addWidget(slid)
def clearLayout(self, layout):
if layout:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget:
widget.deleteLater()
else :
self.clearLayout(item.layout())
layout.removeItem(item)
I'm brand new to Python and I'm trying to make my first program with PyQt4. My problem is basically the following: I have two checkboxes (Plot1 and Plot2), and a "End" push button, inside my class. When I press End, I would like to see only the plots that the user checks, using matplotlib. I'm not being able to do that. My first idea was:
self.endButton.clicked.connect(self.PlotandEnd)
self.plot1Checkbox.clicked.connect(self.Plot1)
self.plot2Checkbox.clicked.conncet(self.Plot2)
def PlotandEnd(self)
plot1=self.Plot1()
pyplot.show(plot1)
plot2=self.Plot2()
pyplot.show(plot2)
def Plot1(self)
plot1=pyplot.pie([1,2,5,3,2])
return plot1
def Plot2(self)
plot2=pyplot.plot([5,3,5,8,2])
return plot2
This doesn't work, of course, because "PlotandEnd" will plot both figures, regardless of the respective checkbox. How can I do what I'm trying to?
Wrap the plot creation in an if statement that looks at the state of the check boxes. For example:
def PlotandEnd(self)
if self.plot1Checkbox.isChecked():
plot1=self.Plot1()
pyplot.show(plot1)
if self.plot2Checkbox.isChecked():
plot2=self.Plot2()
pyplot.show(plot2)
You also don't need the following lines:
self.plot1Checkbox.clicked.connect(self.Plot1)
self.plot2Checkbox.clicked.conncet(self.Plot2)
This does nothing useful at the moment! Qt never uses the return value of your PlotX() methods, and you only want things to happen when you click the End button, not when you click a checkbox. The PlotX() methods are only currently useful for your PlotandEnd() method.
I've a Dialog window with some QLineEdits to insert the data in my software, I Switch from first QLineEdit to the next with TAB key on keyboard
I want the background to change its color to (for example) Yellow and when is focused out (the focus is switched to another) it must go back to White a QLineEdit is Focused,the . for doing this, I inserted a Different StyleSheet in FocusInEvent and FocusOutEvent.
But i have a problem...
The Problem is When i focus on QlineEdit it works (The background change color to yellow) but if i write something and i switch to the next QLineEdit. the TextCursor in the last QlineEdit doesn't disappear and I view two or also more Text Cursors in my window.
*I omit part of source code (Like=>Layout, Database Functions, etc..) because I think they are irrelevant for helping me to fix my problem.
from PyQt4 import QtGui,QtCore;
class AddWindow(QtGui.QDialog):
def __init__(self):
QtGui.QDialog.__init__(self);
#Surname
self.SurnameLabel=QtGui.QLabel("Surname:",self);
self.SurnameLabel.move(5,20);
self.SurnameBox=QtGui.QLineEdit(self);
self.SurnameBox.move(5,35);
self.SurnameBox.focusInEvent=self.OnSurnameBoxFocusIn;
self.SurnameBox.focusOutEvent=self.OnSurnameBoxFocusOut;
#Name
self.NameLabel=QtGui.QLabel("Name:",self);
self.NameLabel.move(150,20);
self.NameBox=QtGui.QLineEdit(self);
self.NameBox.move(150,35);
self.NameBox.focusInEvent=self.OnNameBoxFocusIn;
self.NameBox.focusOutEvent=self.OnNameBoxFocusOut;
def OnSurnameBoxFocusIn(self,event):
self.SurnameBox.setStyleSheet("QLineEdit {background-color:yellow}");
def OnSurnameBoxFocusOut(self,event):
self.SurnameBox.setStyleSheet("QLineEdit {background-color:white}");
def OnNameBoxFocusIn(self,event):
self.NameBox.setStyleSheet("QLineEdit {background-color:yellow}");
def OnNameBoxFocusOut(self,event):
self.NameBox.setStyleSheet("QLineEdit {background-color:white}");
The problem is your implement some event is important of cursor behavior and your code has been interrupt it. To fix it please get old behavior back them after your code has work successful;
def OnSurnameBoxFocusIn(self,event):
self.SurnameBox.setStyleSheet("QLineEdit {background-color:yellow}");
QtGui.QLineEdit.focusInEvent(self.SurnameBox,event) # <- put back old behavior
def OnSurnameBoxFocusOut(self,event):
self.SurnameBox.setStyleSheet("QLineEdit {background-color:white}");
QtGui.QLineEdit.focusOutEvent(self.SurnameBox,event) # <- put back old behavior
def OnNameBoxFocusIn(self,event):
self.NameBox.setStyleSheet("QLineEdit {background-color:yellow}");
QtGui.QLineEdit.focusInEvent(self.NameBox,event) # <- put back old behavior
def OnNameBoxFocusOut(self,event):
self.NameBox.setStyleSheet("QLineEdit {background-color:white}");
QtGui.QLineEdit.focusOutEvent(self.NameBox,event) # <- put back old behavior
Regards,
well I'm using Pyqt4 in Maya2012 to make a reference editor alike ui. I working with a QtableWidget to make the reference list and i have subwidgets in each cell. One of the widgets is a checkbox that unload or reload the reference.
The problem i have is if a click directly in the checkbox without have the cell selected it doesn't do anything
this is my code:
def listConnections(self):
self.pos=self.sender().currentRow()
wid = self.list.ref_l.cellWidget(self.pos, 0).children()
self.text = self.list.list[self.pos]
self.ref()
for wt in wid:
if type(wt)== type(QCheckBox()):
wt.stateChanged.connect(self.changeState)
if type(wt)== type(QComboBox()):
wt.currentIndexChanged.connect(self.changeType)
I'm calling the function with a "itemSlectionChanged" signal because is the only way i knew i could detect the subwidgets.
All the subwidgets are made in the moment i fill the list.
Is there a way to make what i want?
Edit:
This is how i called the function
self.list.ref_l.itemSelectionChanged.connect(self.listConnections)
and this is how i create all the subwidgets in the cells
def fillList(self):
mayaRef = self.findRef()
if len(mayaRef)>0:
for count in range(0,len(mayaRef)):
self.ref_l.insertRow(count)
wid=QWidget()
cLayout=QHBoxLayout()
wid.setLayout(cLayout)
checkWid=QCheckBox()
nameWid=QLabel()
cLayout.addWidget(nameWid)
nameWid2=QLabel()
cLayout.addWidget(nameWid2)
comWid=QComboBox()
cLayout.addWidget(comWid)
self.ref_l.setCellWidget(count,0,wid)
self.ref_l is my QTable Widget, this is in another code that i'm calling with self.list in the original
You should set up all your connections right after you create the check boxes in fillList. Each item is associated with the path of the reference. You can use a QSignalMapper to map each check box to the path, then connect the signal mapper to your changeState slot. The signal mapper then calls that slot with the path you specified.
I'm learning creating software with Python and Tkinter. Now I need to change menu items for different conditions, but could not find an easy way to do it. Well, let me try to explain my question clearly using an example:
Like shown in the figure, I have a listbox on the left and a listbox on the right. I also have a menu to move the items around, the commands are "move to right", "move to left" and "exchange". The following conditions are considered:
When I only get items selected in left listbox, I want only the command "move to right" enabled, like shown in the figure.
When I only get items selected in right listbox, I want only the command "move to left" enabled.
When I get items selected in both listboxes, I want all commands enabled.
When I get no item selected, I want all commands disabled.
I know I can get the work done by binding events "ListboxSelect" and "Button-1" to some functions, and then use the functions to configure the menu. But it is really a complex work when I have five listboxes in the actual software. So I am wondering whether there is an easy way to do this, like overloading some functions in tkinter.Menu class (I tried overloading post(), grid(), pack() and place(), none of them works).
Any idea is welcomed.
I think what you want to use is the postcommand to modify the menu as appropriate. If you're going to have multiple listboxes, the simplest solution may be to implement your own class. Here's a rough idea:
class EditMenu(Tkinter.Menu):
def __init__(self, parent, listboxes, **kw):
self.commandhook = kw.get('postcommand', None)
kw['postcommand'] = self.postcommand
super(EditMenu, self).__init__(parent, **kw)
self.listboxes = listboxes
self.add_command(label="Move to right", command=self.move_to_right)
self.add_command(label="Move to left", command=self.move_to_left)
self.add_command(label="Exchange", command=self.exchange)
def postcommand(self):
for i in xrange(3):
# do some checks for each entry
# and set state to either Tkinter.DISABLED or Tkinter.NORMAL
self.entryconfig(i, state=state)
if self.commandhook is not None:
self.commandhook()
# Implement your three functions here
If you start to add more items, probably what you'll want to do is create a class for each menu item. In that class you could put in the logic for enable/disable and the callback function implementation. Comment if you'd like to see an example.