Communication between mianwindow and dialog in python - python

Hello I am working on data archive program with python 2.7. I have one mainWindow and there is some elements (Buttons, text lines etc.) Clicking a button open a dialog form page. User select their answer on that dialog page. Dialog page has a button named 'save'. When clicking save button dialog class saving user's selections to database. I want to do, when user clicked to save button on dialog, It will enable some elements on the mainWindow which is not enabled. I am doing this with these codes entering to dialog class and save button function:
self.ui.onceBut.setEnabled(True) etc.
But I am taking an error:
AttributeError: 'onceDlg' object has no attribute 'onceBut'
onceDlg is dialog pages class name.
How can I solve this and I can do what I want? Thanks in advance.

self in self.ui.onceBut.setEnabled(True) refers to dialog, so you get error because your onceBut is in your mainWindow not in onceDlg dialog.
Solution: as #Radio say - Communication between components in Qt are often done using signals and slots, but it's not the only way.
Easier way is to simply pass main window to dialog window, so you can manipulate with it's buttons, or whatever you want, inside dialog window. In next example I've done that in line dialog = Dialog(self), where self refers to MainWindow and it is used as mainWin inside Dialog. Run it, click on first button, dialog will show, click save button in dialog and second button in main will be changed and disabled.
I hope I've helped you.
import sys
from PyQt4 import QtCore, QtGui
class Dialog(QtGui.QDialog):
def __init__(self, mainWin):
QtGui.QDialog.__init__(self,mainWin)
self.setWindowTitle(self.tr("Dialog window"))
self.main = mainWin
button = QtGui.QPushButton()
button.setText( "Save (disable dummy button)" )
layout = QtGui.QVBoxLayout()
layout.addWidget(button)
self.setLayout(layout)
self.connect(button, QtCore.SIGNAL("clicked()"), self.save)
self.resize(200, 100)
def save(self):
self.main.button2.setEnabled(False)
self.main.button2.setText( "changed from dialog" )
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle(self.tr("Main window"))
self.button1 = QtGui.QPushButton()
self.button2 = QtGui.QPushButton()
self.button1.setText( "Open dialog" )
self.button2.setText( "Dummy" )
layout = QtGui.QVBoxLayout()
layout.addWidget(self.button1)
layout.addWidget(self.button2)
self.window = QtGui.QWidget()
self.window.setLayout(layout)
self.setCentralWidget(self.window);
self.connect(self.button1, QtCore.SIGNAL("clicked()"), self.showDialog)
self.resize(360, 145)
def showDialog(self):
dialog = Dialog(self)
dialog.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show();
sys.exit(app.exec_())

Related

Notification when QDockWidget's tab is clicked?

I need to execute a block of code when the user clicks on the tab of a tabbified QDockWidget. So far I've been doing this via a hack using the "visibilityChanged" event but this is now causing issues (for example, if I have several tabbified dock widgets and I drag one out so that it is floating, the tabbified one underneath will fire its "visibilityChanged" event which I will mistakenly interpret as the user clicking the tab). How can I receive proper notification when a user clicks on a QDockWidgets' tab? I've experimented with the "focusInEvent" of QDockWidget but it doesn't seem to fire when the tab is clicked.
When you use tabifyDockWidget() method QMainWindow creates a QTabBar, this is not directly accessible but using findChild() you can get it, and then use the tabBarClicked signal
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
first_dock = None
for i in range(10):
dock = QtGui.QDockWidget("title {}".format(i), self)
dock.setWidget(QtGui.QTextEdit()) # testing
self.addDockWidget(QtCore.Qt.TopDockWidgetArea, dock)
if first_dock:
self.tabifyDockWidget(first_dock, dock)
else:
first_dock = dock
dock.raise_()
tabbar = self.findChild(QtGui.QTabBar, "")
tabbar.tabBarClicked.connect(self.onTabBarClicked)
def onTabBarClicked(self, index):
tabbar = self.sender()
text = tabbar.tabText(index)
print("index={}, text={}".format(index, text))
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

In python, how do I open a new window by clicking a button in a main window using .py files created from .ui files made in QtDesigner?

I have two .py files created from .ui files made in QtDesigner. One is a main window for the program, and the other is a widget that allows users to input information and I'm calling it the "evaluation" widget.
I have a button in the main window called "btn_StartNew", which is meant to open the widget window to allow the user to start a new evaluation. I'm having troubles with opening the main window, and adding the function to the "btn_StartNew" button that opens the "evaluation" widget.
The code I have right now opens both the main window and the evaluation widget in the same window when I run the code:
import sys
from PyQt4 import QtCore, QtGui
from wid_Main import Ui_wid_Main
from wid_Eval_v2 import Ui_wid_Eval
class Win_Eval(QtGui.QWidget):
def __init__(self, parent=None):
super(Win_Eval, self).__init__(parent)
self.ui=Ui_wid_Eval()
self.ui.setupUi(self)
class Win_Main(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Win_Main, self).__init__(parent)
self.ui=Ui_wid_Main()
self.ui.setupUi(self)
#RUN "start new eval" button
self.ui.btn_StartNew.clicked.connect(self.btn_StartNew_click)
self.dialog = Win_Eval(self)
def btn_StartNew_click(self):
self.dialog.show()
def main():
app = QtGui.QApplication(sys.argv)
main = Win_Main()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Where wid_Main and Ui_wid_Main are the main window file and the main window class, respectively. And wid_Eval_v2 and Ui_wid_Eval are the evaluation widget file and class, respectively.
Any help would be much appreciated!
You must change:
self.dialog = Win_Eval(self)
to
self.dialog = Win_Eval()

PyQt: Accesing Main Window's Data from a dialog?

So, I'm using Python and PyQt. I have a Main Window that contains a QTableWidget, and a dialog that opens modally and has some QLineEdit widgets... All right so far, but I have 2 problems:
When the dialog opens, my Main Window freezes, and I don't really like that...
What I want, when I finish editing a QLineEdit, is that the program will search the QTableWidget, and if the text from the QLineEdit exists in the table, a dialog will come up and informe about that. That's the general idea. But, so far, I seem to only be able to create a new QTableWidget instance, and I can't use the data from the existing...
What can I do about these?
You wrote:
and a dialog that opens modally
and then:
When the dialog opens, my Main Window freezes
The docs say:
int QDialog::exec () [slot]
Shows the dialog as a modal dialog,
blocking until the user closes it. The function returns a DialogCode
result. If the dialog is application modal, users cannot interact with
any other window in the same application until they close the dialog.
If the dialog is window modal, only interaction with the parent window
is blocked while the dialog is open. By default, the dialog is
application modal.
About modeless dialogs:
A modeless dialog is a dialog that operates independently of other
windows in the same application. Find and replace dialogs in
word-processors are often modeless to allow the user to interact with
both the application's main window and with the dialog.
Modeless
dialogs are displayed using show(), which returns control to the
caller immediately.
An example:
import sys
from PyQt4 import QtCore, QtGui
class SearchDialog(QtGui.QDialog):
def __init__(self, parent = None):
QtGui.QDialog.__init__(self, parent)
self.setWindowTitle('Search')
self.searchEdit = QtGui.QLineEdit()
layout = QtGui.QVBoxLayout()
layout.addWidget(self.searchEdit)
self.setLayout(layout)
class MainWindow(QtGui.QDialog):
def __init__(self):
QtGui.QDialog.__init__(self, None)
self.resize(QtCore.QSize(320, 240))
self.setWindowTitle('Main window')
self.logText = QtGui.QPlainTextEdit()
searchButton = QtGui.QPushButton('Search')
layout = QtGui.QVBoxLayout()
layout.addWidget(self.logText)
layout.addWidget(searchButton)
self.setLayout(layout)
searchButton.clicked.connect(self.showSearchDialog)
def showSearchDialog(self):
searchDialog = SearchDialog(self)
searchDialog.show()
searchDialog.searchEdit.returnPressed.connect(self.onSearch)
def onSearch(self):
self.logText.appendPlainText(self.sender().text())
def main():
app = QtGui.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
app.exec_()
if __name__ == "__main__":
main()
Click 'Search' to open a search window (you can open several of them). Enter a text to search and press Enter. The text to search will be added to the log in the main window.

uncheck radiobutton - PyQt4

In this sample of code:
from PyQt4.QtGui import QDialog, QPushButton, QRadioButton, QHBoxLayout, QApplication, QButtonGroup
import sys
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent=None)
button = QPushButton('Button')
self.radiobutton1 = QRadioButton('1')
self.radiobutton2 = QRadioButton('2')
#self.group = QButtonGroup()
#self.group.addButton(self.radiobutton1)
#self.group.addButton(self.radiobutton2)
#self.group.setExclusive(False)
layout = QHBoxLayout()
layout.addWidget(button)
layout.addWidget(self.radiobutton1)
layout.addWidget(self.radiobutton2)
self.setLayout(layout)
button.clicked.connect(self.my_method)
def my_method(self):
self.radiobutton1.setChecked(False)
self.radiobutton2.setChecked(False)
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
When the button clicked I expect the selected radioButton to be unchecked, but that never happens. If I uncomment the comment lines and run the code, then I can uncheck radioButtons. But another problem occurs. Because the group is not exclusive, I can set both radioButtons checked something that must not happens.
What should I do to be able to unckeck the buttons while only one button at a time can be selected?
This feels like cheating, but it works:
import sys
import PyQt4.QtGui as QtGui
class Form(QtGui.QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
button = QtGui.QPushButton('Button')
button.clicked.connect(self.my_method)
self.radiobutton1 = QtGui.QRadioButton('1')
self.radiobutton2 = QtGui.QRadioButton('2')
layout = QtGui.QHBoxLayout()
layout.addWidget(button)
layout.addWidget(self.radiobutton1)
layout.addWidget(self.radiobutton2)
self.setLayout(layout)
self.group = QtGui.QButtonGroup()
self.group.addButton(self.radiobutton1)
self.group.addButton(self.radiobutton2)
def my_method(self):
self.group.setExclusive(False)
self.radiobutton1.setChecked(False)
self.radiobutton2.setChecked(False)
self.group.setExclusive(True)
app = QtGui.QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
As you've pointed out, when self.group.setExclusive(False) is set, you can untoggle both radio buttons.
And when self.group.setExclusive(True), only one radio button can be set.
So my_method simply calls self.group.setExclusive(False) so it can unset both radio buttons, then resets self.group.setExclusive(True).
PS. I think parent should not be set to None on this line:
super(Form, self).__init__(parent = None)
since if a non-trivial parent is sent to Form, you would probably want to pass that parent on to QDialog.__init__.
To anyone looking for a simple fix to this very annoying problem, connect each button to a slot that controls the CheckState of the other buttons.
Simply add the list of buttons you want to a QButtonGroup, get the list of buttons, check that the sender is not the same button, and uncheck others.
Assuming that you instantiate your buttons in a loop, you can easily implement this:
self.bg = QButtonGroup()
self.bg.setExclusive(False)
for button in list_of_buttons:
self.bg.addButton(button)
button.clicked.connect(self.uncheck_other_buttons)
def uncheck_other_btns(self):
for button in self.bg.buttons(): # returns the list of all added buttons
if self.sender() != button: # in PyQt5, button.objectName() fails if name isn't set,
# instead, simply check that the signal sender() object
# is not the same object as the clicked button
button.setChecked(False) # then set all other buttons to be unchecked

Right click contextMenu on QPushButton

For my app I have created a GUI in Qt Designer and converted it into python(2.6) code.
On some of the QPushButton (created with the designer) I want to add a right click context menu. The menu options depend on the application status.
How to implement such a context menu ?
Check if an example below would work for you. The key thing is to set context menu policy for your widget to CustomContextMenu and connect to the widget's customContextMenuRequested signal:
import sys
from PyQt4 import QtGui, QtCore
class MainForm(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainForm, self).__init__(parent)
# create button
self.button = QtGui.QPushButton("test button", self)
self.button.resize(100, 30)
# set button context menu policy
self.button.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.button.customContextMenuRequested.connect(self.on_context_menu)
# create context menu
self.popMenu = QtGui.QMenu(self)
self.popMenu.addAction(QtGui.QAction('test0', self))
self.popMenu.addAction(QtGui.QAction('test1', self))
self.popMenu.addSeparator()
self.popMenu.addAction(QtGui.QAction('test2', self))
def on_context_menu(self, point):
# show context menu
self.popMenu.exec_(self.button.mapToGlobal(point))
def main():
app = QtGui.QApplication(sys.argv)
form = MainForm()
form.show()
app.exec_()
if __name__ == '__main__':
main()

Categories