I'm using PyQt5 to create a program. I created 3 Radio Buttons, but when I check the first button and check the second button after that. The program will run both of the functions which are connected to these buttons. How I can make it only run the function which is connected to that button. Thanks.
def __init__(self):
super(Program, self).__init__()
self.ui = Ui_APIManager()
self.ui.setupUi(self)
self.show()
self.ui.add_btn.toggled.connect(self.start)
self.ui.check_btn.toggled.connect(self.start)
self.ui.delete_btn.toggled.connect(self.start)
def start(self):
if self.ui.add_btn.isChecked():
self.ui.third_lbl.setEnabled(True)
self.ui.first_lbl.setText('Tool name')
self.ui.second_lbl.setText('ID')
self.ui.third_lbl.setText('Username')
self.ui.action_btn.clicked.connect(self.add_user)
elif self.ui.check_btn.isChecked():
self.ui.first_lbl.setText('Type of search')
self.ui.second_lbl.setText('Keyword')
self.ui.third_lbl.setEnabled(False)
self.ui.action_btn.clicked.connect(self.check_user)
elif self.ui.delete_btn.isChecked():
self.ui.first_lbl.setText('Type of search')
self.ui.second_lbl.setText('Keyword')
self.ui.third_lbl.setEnabled(False)
self.ui.action_btn.clicked.connect(self.delete_user)
Qt signals can have multiple slots attached to them. Every time you click a button the start function is adding another connection to the action_button.clicked signal.
You will need to disconnect any existing slots from the signal first to achieve the desired behaviour. You can disconnect everything from self.ui.action_btn all at once by calling its disconnect() function.
Rather than trying to reassign the roles of the GUI elements you have created, you would be better off creating separate widgets containing the elements for each checkbox state and switching between them. You might find QStackedWidget useful.
Related
Basically I have created a Dialog without buttons window as an alert box using Qt5 designer and compiled to Python using Pyuic5 which resulted into partial code as below:
class Ui_alertwindow(object):
def setupUi(self, alertwindow):
alertwindow.setObjectName("alertwindow")
alertwindow.resize(400, 300)
alertwindow.setStyleSheet("background:#222;")
# much more code
Later on, I will have to modify parts of this window which I could not using Qt5 designer, hence I created a separate class to make the changes, as below:
class alertWindowCustom(QDialog, Ui_alertwindow):
def __init__(self):
QDialog.__init__(self)
self.setupUi(self)
self.run()
def run(self):
print("Changes will be made here")
And then finally call this function in QMainWindow when a button is pressed:
def CreateAlertWindow(self):
alertWindow = alertWindowCustom()
alertWindowInput = alertWindow.exec_()
This creates a white dialog box while not responding and in the console I am getting below errors:
Changes will be made here
Unknown property justification
Unknown property justification
QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
Can anyone tell me what is wrong here?
I wrote a python GUI program consisting of two separate files; One is for logic code and the other for GUI using PyQt4. The behaviour of some objects (buttons, text fields ...) changes throughout the code and I need to reset everything to its original status by clicking on a QAction class menu item. How can I do that?
EDIT: the function that supposed to reset the GUI to the original status:
def newSession(self):
self.ui.setupUi(self)
self.filename = ""
self.paramsSplitted = []
self.timestep = None
self.index = None
self.selectedParam = None
self.selectedMethod = None
--Snip--
What you could do:
Define a ResetHandler(QtCore.QObject) object with a reset_everything signal
During startup create an instance and set it on the globally available QApplication like qapplication.reset_handler = ResetHandler()
Every UI element that needs to update itself defines a on_reset_everything_triggered() slot. (Optional: You could also just use update for example).
When You create UI elements that are supposed to update, connect them to the globally available reset_everything signal from the handler on the QApplication.
Connect your QAction.triggered with the ResetHandler.reset_everything signal.
Now every time you press the QAction the reset_everything signal is invoked, and all UI elements that you connected will update themself.
Like you requested in your comment here is a schematic way of utilizing a function to connect all signals and the method setupUi.
class MainWindow(QtGui.QMainWindow) :
def __init__(self) :
QtGui.QMainWindow.__init__(self)
self.ui.setupUi(self)
# Some code
self.connectAllSignals()
def connectAllSignals(self) :
self.someWidget.clicked.connect(self.someFunction)
self.someAction.triggered.connect(self.otherFunction)
# All the other signals
def disconnectAllSignals(self) :
try :
self.someWidget.clicked.disconnect()
self.someAction.triggered.disconnect()
# All the other signals
except :
print("Something went wrong. Check your code.")
pass
def newSession(self) :
self.ui.setupUi(self)
self.disconnectAllSignals()
self.connectAllSignals()
# Do whatever it takes
By this you ensure you have only the initial settings for your signals and all dynamically added connections are broken. In the method disconnectAllSignals be sure all widgets exist and all signals have at least one connection by the time you call it. If you have new widgets invoked dynamically you should consider deleting them in th method newSession after calling connectAllSignals.
I'd like to create a dynamic menu which enumerates all QDockWidget from my QMainWindow and allows to show/hide the QDockWidgets, so far I got this code:
class PluginActionsViewDocks():
def __init__(self, main_window):
self.main_window = main_window
mapper = QSignalMapper(self.main_window)
self.actions = []
for dock in main_window.findChildren(QtWidgets.QDockWidget):
action = create_action(
main_window, dock.windowTitle(),
slot=mapper.map,
tooltip='Show {0} dock'.format(dock.windowTitle())
)
mapper.setMapping(action, dock)
self.actions.append(action)
mapper.mapped.connect(self.toggle_dock_widget)
help_menu = main_window.menuBar().addMenu('&View')
setattr(help_menu, "no_toolbar_policy", True)
add_actions(help_menu, tuple(self.actions))
def toggle_dock_widget(self, dock_widget):
print("toggle_dock_widget")
The menu is populated with all QDockWidget windowTitles but when i press each of them the slot toggle_dock_widget is not called. create_action is a helper which creates the QAction and connect the triggered signal to slot.
The thing is, I don't really understand quite well how QSignalMapper works but my intuition tells me it's the right choice for this particular problem.
What could I be missing here?
There's aleady a built-in dock-widget menu. Just right-click any dock title-bar, or any tool-bar or menu-bar. See: QMainWindow::createPopupMenu.
PS:
The reason why your QSignalMapper code doesn't work is probably because you are connecting to the wrong overload of the mapped signal. Try this instead:
mapper.mapped[QtWidgets.QWidget].connect(self.toggle_dock_widget)
I am new to PyQt4 and after several searches I have not found info on the issue I am seeing in my GUI.
The issue is that when a user clicks on getSingleItems button, the function runs the same amount of times that the user has clicked getAllItems. An example is if the user clicks getAllItems to populate the items field, and then they click on getSingleItem, getitems runs once and they will get the result printed once per expectation. But if the user selects another item from list and clicks on getAllItems again, then on getSingleItem, the results is that getitem runs 2x and therefore prints 2x. This increments with each run through so clicking getAllItems 4x, even without changing selection, then clicking getitem will run 4x with a single click on getSingleItem. Only way to refresh it is to close the GUI and reopen. Any help is appreciated.
class UpdateItem(QDialog, updateitem_ui.Ui_updateitem):
def __init__(self):
QDialog.__init__(self)
self.setupUi(self)
tests = ['Test1', 'Test2', 'Test3']
self.list.addItems(tests)
self.exit.clicked.connect(self.close)
self.setFocus()
self.getAllItems.clicked.connect(self.getitems)
def getitems(self):
self.items.clear()
self.items.addItems(self.list.currentText())
self.getSingleItem.clicked.connect(self.getitem)
def getitem(self):
self.item_id = self.items.currentText()
print(self.item_id)
app = QApplication(sys.argv)
gui = UpdateItem()
gui.show()
app.exec_()
Apparently you are are adding new connection to getSingleItem.clicked in each run of getitems,
so the clicked signal gets connected multiple times to the same slot,
which causes the behaviour you observe.
Moving the line
self.getSingleItem.clicked.connect(self.getitem)
from getitems to __init__ should fix the issue, I guess.
I have a UI in which it consists of a few QPushButton and a QLineEdit and currently I am having trouble to 'update' the contents within this QMenu that was attached onto a QPushButton.
So assumingly, if there are already 2 cameras in my scene, and as I execute my UI, by pressing onto this setCameraBtn I will get the 2 cameras in the list. However, if I create a new camera where the UI is not yet close, how do I make my QMenu to read in the new camera, like a 'live-update'?
I tried creating another function where it re-read the cameras in scene and retabulate the camLs as well as a connection similar to the one that I have written in the createConnections but it does not seems to be reading in.
camLs = []
class orientCameraUI(QDialog):
def __init__(self, parent=None):
...
...
def initUI(self):
...
...
def createConnections(self):
self.connect(self.orientToCamBtn, SIGNAL('clicked()'), self.orientToCam)
def camMenu(self):
allCams = [cam for cam in cmds.listRelatives(cmds.ls(cameras=1),parent=1) if cam not in ['front','persp','side','top']]
camLs.extend(allCams)
menu = QMenu("menu", self.setCameraBtn)
for item in camLs:
menu.addAction(QAction(item, menu))
self.setCameraBtn.setMenu(menu)
menu.triggered.connect(self._camSelected)
def _camSelected(self, action):
self.currentCamTxt.setText(action.text())
This can be easily accomplished by firing a QThread instead the UI that periodically call a update camera method which checks for the current cameras in the scene and compares them with the one that the UI has already registered. And if there is an addition, change or deletion in the camera(s) then it updates the menu to reflect it.
Another solution is to use scriptJob.