Solved Confirm login dialog and show main windows pyqt5
-
I wrote main windows and now i added login form i want it if the user close the form main windows not start and if confirm the user form close and main windows shows up:
def setupUi(self, MainWindow): .............. self.loginForm()
def loginForm(self): self.dialog = QDialog() self.dialog.ui = Ui_UsrDialog() self.dialog.ui.setupUi(self.dialog) self.dialog.setStyleSheet(open('matt.css').read()) self.dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose) if ( not self.dialog.exec_() ): sys.exit(0)
Dialog form button click function called register :
def register(self): print("clicked") if self.lineEditUser.text() == "user" and self.lineEditPass.text()== "12345": self.hide() # not work what should i write here
-
@behruz-montazeri
Do not useself.hide()
. For (modal) dialog you use eitherself.accept()
, orself.reject()
, to exit and returnTrue
/False
back todialog.exec()
as return result. -
@JonB
No change when i use either self.reject() or self.accept(). I need to confirm user and password and then back to main window.def register(self): print("clicked") if self.lineEditUser.text() == "user" and self.lineEditPass.text()== "12345": self.accept() # not work also self.reject()
-
@behruz-montazeri
It's "self
". You have to write your code inside the dialog code, in response to a button click. I don't know where yourregister
method is. Look up https://doc.qt.io/qt-5/qdialog.html#accept etc. for yourself. It's the way allQDialog
stuff works, so something wrong with whatever you are doing if it does not. -
@JonB
It's a pushButton click inside the dialog form(class)self.btnReg.clicked.connect(self.register)
-
@behruz-montazeri
But it's the dialog fromself.dialog.exec_()
that you want the button to exit, right? So then clearly it would beself.dialog.accept()
?Usually you write handlers (slots) for a dialog in the dialog class's code (by sub-classing the dialog), not in the caller's code. I get mixed up the way you have done it. Your dialog widgets like
lineEditUser
&lineEditPass
are members ofself
butself
is not the dialog they appear on but rather the form which opens the dialog, is that right? Confusing! -
@JonB
i guess it better to be dialog.exec_() instead of self.dialog.exec_(). The actual dialog has two button exit button and register button. -
@behruz-montazeri
This is main window:class Ui_MainWindow(object): def setupUi(self, MainWindow): self.loginForm() def loginForm(self): dialog = QDialog() dialog.ui = Ui_UsrDialog() dialog.ui.setupUi(dialog) dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose) if ( not dialog.exec() ): sys.exit(0) if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())
This is dialog form:
class Ui_UsrDialog(QtWidgets.QDialog): def __init__(self): super(Ui_UsrDialog, self).__init__() self.setupUi(self) def setupUi(self, Dialog): self.btnReg.clicked.connect(self.register) def register(self): if self.lineEditUser.text() == "1" and self.lineEditPass.text()== "1": self.accept() # not work also self.reject()
-
@behruz-montazeri
OK. Look, you originally said:Dialog form button click function called register :
But I do not see anywhere that does actually call your
register()
. Put in debug statement likeprint()
to prove when it calls yourregister()
.I see only that
btnExit
callsself.closeFrm()
, and I do not see that function defined either.I can only tell you: if the outside world calls
QDialog.exec()
, then that will return, withTrue
, if your button'sclicked
callsaccept()
. -
@JonB
I missed to write the call of register function. I edited the post. Yes print statement print when i click and when the condition meet. -
This post is deleted! -
@JonB
Eventually i get it working by :self.btnReg.clicked.connect(lambda: self.register(Dialog))
And :
def register(self,Dialog): if self.lineEditUser.text() == "1" and self.lineEditPass.text()== "1": print("clicked") Dialog.accept()
-
@behruz-montazeri
Yes, because finally you are callingaccept()
on the dialog instance!I think you are learning Qt & PyQt. Even though what you have now works, I think you should consider rewriting a bit, so that going forward your coding style will be better.
One small point is: don't name your variables starting with an upper-case letter, only do that for your classes. So your
Dialog
parameter should be speltdialog
instead.A bigger point is what I said about where you define your methods and what
self
is. You have keptself
being your form, even when you are in code which is executing in the dialog. And you have member variables likeself.lineEditUser
&self.lineEditPass
which are for widgets on the dialog, even thoughself
is the form. This is not good for anybody.A much better pattern is to sub-class your dialog instance from
QDialog
, and put the dialog's variables & methods in that sub-class, not in your form code which calls the dialog. (Oh, I see you have begun to do that, but not fully completed.) It will make your code much easier to understand & maintain in the long run. Your code should be written more like the following:class MyDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.btnReg.clicked.connect(self.register) def register(self): if self.lineEditUser.text() == "1" and self.lineEditPass.text()== "1": self.accept() def loginForm(self): self.dialog = MyDialog(self) ... if self.dialog.exec(): ....
This assumes that
btnReg
,lineEditUser
&lineEditPass
are all on the dialog. Note how we define theregister()
method as a member of the dialog, not of the form, and duringregister()
theself
refers to the dialog itself, not the form. That's where it belongs. -
@Denni-0 said in Confirm login dialog and show main windows pyqt5:
For this very reason within my code I capitalize most of my variable/methods/classes some of which will get a type prefix in lower case
.
Now were I writing code to be consumed by the general public then I would conform more to this standard put forth by @JonB but when I am not I use my standard. This is where Style is something that is what you choose versus Standards which are wiredWell, you have had your say and you have your opinion, which is fair enough. But Python (as well as C++) convention on this is clear enough (e.g. https://www.python.org/dev/peps/pep-0008). Now, in Python one is supposed to use underscores (snake_case) rather than camel-case, but there are plenty of examples out there of people using camelCase, and in the case of PyQt there is good reason to accept that in order to be consistent with the whole of the Qt libraries you are using which universally adopts the camelCase on variables/functions while using Upper Camel Case on types, and is precisely what the author of PyQt chose when implementing.
IMHO encouraging people to use "personal styles" when coding "not for public" is not good. I mean it politely, and doubtless we will agree to differ. I don't think anyone else on this forum would suggest "personal styling" like this, So at least the OP has a choice.
-
@Denni-0 said in Confirm login dialog and show main windows pyqt5:
@pyqtSlot() def Register(self): if self.lneUserName.text() == "1" and self.lneUserPass.text()== "1": self.Parent.UsrRegd = True self.close()
I would advise the OP absolutely not to do it this way. This was the whole point of learning to use
QDialog.accept()
etc. Doing stuff viaself.Parent.UsrRegd = True
where you write into
self.Parent
is wrong for so many reasons (not the least of which is that it may well crash). Again, if you don't agree, I'll leave it to others here to debate the case, but this is an anti-pattern beginners should not be using..... This one matters. -
@Denni-0
Briefly.And I would challenge you to back up your fictitious statement with some actual hard facts on how this is going to make your program crash or adversely affect it in anyway
I was polite to you, it's not a "fictitious" statement. The default constructor for
QDialog
isQDialog(parent=None)
. That will mean yourUserLogin
will haveself.Parent is None
when invoked asdialog = UserLogin()
. And then yourself.Parent.UsrRegd = True
will "crash" (or at least throw an exception from Python, which is all I meant).Writing code which has one object read/write into another object when there is absolutely no need to do so breaks the principles of OO. The code only works if a parent is passed in and the parent has a member variable named
UsrRegd
for the result. Fortunately, only Python lets you do that, it would not compile from C++. Making one object's code only work when called in a certain fashion from the outside world is not good, and it's not a good example to set for beginners. There are times when a "child" does need to access its parent, but this is not one of them.Meanwhile, Qt has perfectly good, documented, intended mechanism that
QDialog::exec()
returns true/false to the caller according as it invokesQDialog.accept()/reject()
. From https://doc.qt.io/qt-5/qdialog.html#details:The most common way to display a modal dialog is to call its
exec()
function. When the user closes the dialog,exec()
will provide a useful return value. Typically, to get the dialog to close and return the appropriate value, we connect a default button, e.g. OK, to theaccept()
slot and a Cancel button to thereject()
slot. Alternatively you can call thedone()
slot withAccepted
orRejected
.and
Return Value (Modal Dialogs)
Modal dialogs are often used in situations where a return value is required, e.g. to indicate whether the user pressed OK or Cancel. A dialog can be closed by calling the
accept()
or thereject()
slots, andexec()
will return Accepted or Rejected as appropriate. Theexec()
call returns the result of the dialog.That is what all examples will use. If any other experts here would care to comment, or if you asked this on, say, stackoverflow, I think you would find you got the same response. Whether that would convince you I do not know.
-
Hi,
To add to @JonB, this
self.Parent.UsrRegd = True
has a name: tight coupling.
This is the open door to maintenance hell. Having a child manipulate the internals of its parent is usually sign of architecture problems.
There's signals and slots for interaction or setters/getters but the child shall never care about the class that is using it, it is not its role. -
Setting directly a variable value in a parent class is not a callback.
Also, callbacks are provided to classes that ignores completely how the class that is setting said callback works. Which again avoids tight coupling which is the point currently debated.
-
@Denni-0 said in Confirm login dialog and show main windows pyqt5:
Now were I writing code to be consumed by the general public then I would conform more to this standard put forth by @JonB but when I am not I use my standard.
Mmm, it seems not a well thought decision.
What if something you wrote "internally" has now the opportunity "to be consumed by the general public"?
Are you going to jump and re-write such code?
I cannot stand but think about "there's no second chance for first impressions"self.Parent.UsrRegd = True
As several people already mentioned, tight coupling and not a good approach detectors are firing up here.
What if you have written a modular dialog you intend to reuse in several parts of your application? You're imposing that the parent class have such property.
Again, it doesn't seem smart. -
@JonB
I generated the dialog form via designer and it by default makes Dialog capitalized.def setupUi(self, Dialog): ........................................................... def setupUi(self, Form): Form.setObjectName("Form") Form.resize(400, 300)
I really appreciate your hint and help.that was a grand help. I should use it as my correct workflow.