Python Forum
Running external Python file as a subwindow - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: GUI (https://python-forum.io/forum-10.html)
+--- Thread: Running external Python file as a subwindow (/thread-34491.html)

Pages: 1 2


Running external Python file as a subwindow - JayCee - Aug-04-2021

Hello, everyone. I am a beginner programmer developing an MDI application. So far, I have two files:

main.py (MainWindow with mdiArea and menuBar)
users.py (window that displays users)

I am able to run the users.py file from main.py by using import subprocess and then calling it:

subprocess.call(["python", "users.py"])

It works, but I need the Users window to be a subwindow in the main application. Can anyone please point me in the right direction? Thanks a lot for your time and help.


RE: Running external Python file as a subwindow - ndc85430 - Aug-04-2021

You're going to need to explain in more detail and show code. It's not clear why you (think you) need a separate process.


RE: Running external Python file as a subwindow - JayCee - Aug-04-2021

I'm developing an MDI application which I know is going to be pretty large. It would make sense to me to split the code instead of having one huge Python file that holds everything. I come from the C# .Net world and I think code-splitting makes it easier to debug, easier to maintain.

The attached screenshot shows the User window outside the mdiArea and I would like to run it inside, otherwise it will totally defeat the purpose of developing an MDI application.


RE: Running external Python file as a subwindow - Axel_Erfurt - Aug-04-2021

Haven't you already achieved that here?

https://python-forum.io/thread-34470-post-145454.html#pid145454


RE: Running external Python file as a subwindow - ndc85430 - Aug-04-2021

Yes, of course splitting an application up into separate files is important in any large project, but what I'm getting at is do those really need to be entirely separate programs? Can't they just be modules with functions and classes that you import where you need them (like one would do in C#, Java or anything else really)? I don't know what MDI is, so I don't know whether it imposes this separate program thing on you.


RE: Running external Python file as a subwindow - JayCee - Aug-04-2021

(Aug-04-2021, 05:28 PM)Axel_Erfurt Wrote: Haven't you already achieved that here?

https://python-forum.io/thread-34470-post-145454.html#pid145454

Nope, because in regards to that Post, the entire code is in the same file and now I want to split the code, otherwise it will be a nightmare to maintain.


RE: Running external Python file as a subwindow - JayCee - Aug-04-2021

They do not have to be separate programs. I guess they could be modules. The question now is how do I make the users.py file a module I can import. Here is the code to my users.py file:

import sys
import pymysql
from datetime import datetime
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMessageBox

rowNo = 1

connection = pymysql.connect(
    host='--------',
    user='--------',
    password='-------',
    db='------------')

cur = connection.cursor()
sql0 = "CREATE TEMPORARY TABLE users_temp AS SELECT * FROM users_view ORDER BY name"
cur.execute(sql0)


class Ui_Dialog(object):
    def setupUi(self, myDialog):
        myDialog.setObjectName("myDialog")
        myDialog.resize(468, 291)

        # ----------------------- Buttons -----------------------
        self.pushButton_first = QtWidgets.QPushButton(myDialog)
        self.pushButton_first.setGeometry(QtCore.QRect(50, 210, 75, 23))
        self.pushButton_first.setObjectName("pushButton_first")

        self.pushButton_previous = QtWidgets.QPushButton(myDialog)
        self.pushButton_previous.setGeometry(QtCore.QRect(140, 210, 75, 23))
        self.pushButton_previous.setObjectName("pushButton_previous")

        self.pushButton_next = QtWidgets.QPushButton(myDialog)
        self.pushButton_next.setGeometry(QtCore.QRect(230, 210, 75, 23))
        self.pushButton_next.setObjectName("pushButton_next")

        self.pushButton_last = QtWidgets.QPushButton(myDialog)
        self.pushButton_last.setGeometry(QtCore.QRect(330, 210, 75, 23))
        self.pushButton_last.setObjectName("pushButton_last")

        self.pushButton_add = QtWidgets.QPushButton(myDialog)
        self.pushButton_add.setGeometry(QtCore.QRect(140, 240, 75, 23))
        self.pushButton_add.setObjectName("pushButton_add")

        self.pushButton_edit = QtWidgets.QPushButton(myDialog)
        self.pushButton_edit.setGeometry(QtCore.QRect(230, 240, 75, 23))
        self.pushButton_edit.setObjectName("pushButton_edit")

        self.pushButton_update = QtWidgets.QPushButton(myDialog)
        self.pushButton_update.setGeometry(QtCore.QRect(230, 240, 75, 23))
        self.pushButton_update.setObjectName("pushButton_update")

        self.pushButton_cancel = QtWidgets.QPushButton(myDialog)
        self.pushButton_cancel.setGeometry(QtCore.QRect(150, 240, 75, 23))
        self.pushButton_cancel.setObjectName("pushButton_cancel")

        self.pushButton_save = QtWidgets.QPushButton(myDialog)
        self.pushButton_save.setGeometry(QtCore.QRect(230, 240, 75, 23))
        self.pushButton_save.setObjectName("pushButton_save")

        self.pushButton_delete = QtWidgets.QPushButton(myDialog)
        self.pushButton_delete.setGeometry(QtCore.QRect(330, 240, 75, 23))
        self.pushButton_delete.setObjectName("pushButton_delete")

        # ----------------------- Input Fields -----------------------
        self.lineEdit_id = QtWidgets.QLineEdit(myDialog)
        self.lineEdit_id.setGeometry(QtCore.QRect(70, 80, 331, 20))
        self.lineEdit_id.setObjectName("lineEdit_id")

        self.lineEdit_name = QtWidgets.QLineEdit(myDialog,  placeholderText="Name")
        self.lineEdit_name.setGeometry(QtCore.QRect(70, 80, 331, 20))
        self.lineEdit_name.setObjectName("lineEdit_name")

        self.lineEdit_login = QtWidgets.QLineEdit(myDialog,  placeholderText="Login")
        self.lineEdit_login.setGeometry(QtCore.QRect(70, 110, 113, 20))
        self.lineEdit_login.setObjectName("lineEdit_login")

        self.lineEdit_pwd = QtWidgets.QLineEdit(myDialog,  placeholderText="Password", echoMode=2)
        self.lineEdit_pwd.setGeometry(QtCore.QRect(70, 140, 113, 20))
        self.lineEdit_pwd.setObjectName("lineEdit_pwd")

        self.reTranslateUi(myDialog)
        QtCore.QMetaObject.connectSlotsByName(myDialog)

    def reTranslateUi(self, myDialog):
        _translate = QtCore.QCoreApplication.translate
        myDialog.setWindowTitle(_translate("myDialog", "Users"))

        self.pushButton_first.setText(_translate("myDialog", "<< First"))
        self.pushButton_first.setObjectName("pushButton_first")
        self.pushButton_first.clicked.connect(ShowFirst)

        self.pushButton_previous.setText(_translate("myDialog", "< Previous"))
        self.pushButton_previous.setObjectName("pushButton_previous")
        self.pushButton_previous.clicked.connect(ShowPrevious)

        self.pushButton_next.setText(_translate("myDialog", "Next >"))
        self.pushButton_next.setObjectName("pushButton_next")
        self.pushButton_next.clicked.connect(ShowNext)

        self.pushButton_last.setText(_translate("myDialog", "Last >>"))
        self.pushButton_last.setObjectName("pushButton_last")
        self.pushButton_last.clicked.connect(ShowLast)

        self.pushButton_add.setText(_translate("myDialog", "Add +"))
        self.pushButton_add.setObjectName("pushButton_add")
        self.pushButton_add.clicked.connect(addRecord)

        self.pushButton_edit.setText(_translate("myDialog", "Edit"))
        self.pushButton_edit.setObjectName("pushButton_edit")
        self.pushButton_edit.clicked.connect(editRecord)

        self.pushButton_save.setText(_translate("myDialog", "Save"))
        self.pushButton_save.setObjectName("pushButton_save")
        self.pushButton_save.clicked.connect(saveRecord)

        self.pushButton_cancel.setText(_translate("myDialog", "Cancel"))
        self.pushButton_cancel.setObjectName("pushButton_cancel")
        self.pushButton_cancel.clicked.connect(cancelAll)

        self.pushButton_update.setText(_translate("myDialog", "Atualizar"))
        self.pushButton_update.setObjectName("pushButton_update")
        self.pushButton_update.clicked.connect(updateRecord)

        self.pushButton_delete.setText(_translate("myDialog", "Delete"))
        self.pushButton_delete.setObjectName("pushButton_delete")
        self.pushButton_delete.clicked.connect(deleteRecord)

        self.pushButton_cancel.hide()
        self.pushButton_save.hide()
        self.pushButton_update.hide()

        ShowFirst()
        lockForm()


def ShowFirst():
    global rowNo
    sql = "SELECT number, name, login, pwd, id FROM users_temp"
    cur.execute(sql)
    row = cur.fetchone()
    if row:
        ui.lineEdit_name.setText(row[1])
        ui.lineEdit_login.setText(row[2])
        ui.lineEdit_pwd.setText(row[3])
        ui.lineEdit_id.setText(str(row[4]))
        rowNo = row[0]
    else:
        QMessageBox.critical(None, "Erro:", "Não foi possível acessar os dados.\n Cheque o servidor.")


def ShowPrevious():
    global rowNo
    rowNo -= 1
    sql = "SELECT number, name, login, pwd, id FROM users_temp WHERE number=%s"
    cur.execute(sql, rowNo)
    row = cur.fetchone()
    if row:
        ui.lineEdit_name.setText(row[1])
        ui.lineEdit_login.setText(row[2])
        ui.lineEdit_pwd.setText(row[3])
        ui.lineEdit_id.setText(str(row[4]))
    else:
        rowNo += 1


def ShowNext():
    global rowNo
    rowNo += 1
    sql = "SELECT number, name, login, pwd, id FROM users_temp WHERE number=%s"
    cur.execute(sql, rowNo)
    row = cur.fetchone()
    if row:
        ui.lineEdit_name.setText(row[1])
        ui.lineEdit_login.setText(row[2])
        ui.lineEdit_pwd.setText(row[3])
        ui.lineEdit_id.setText(str(row[4]))
    else:
        rowNo -= 1


def ShowLast():
    global rowNo
    sql = "SELECT number, name, login, pwd, id FROM users_temp"
    cur.execute(sql)
    for row in cur.fetchall():
        ui.lineEdit_name.setText(row[1])
        ui.lineEdit_login.setText(row[2])
        ui.lineEdit_pwd.setText(row[3])
        ui.lineEdit_id.setText(str(row[4]))
        rowNo = row[0]


def addRecord():
    clearAll()
    ui.pushButton_edit.hide()
    ui.pushButton_delete.hide()
    ui.pushButton_add.hide()
    ui.pushButton_first.hide()
    ui.pushButton_previous.hide()
    ui.pushButton_next.hide()
    ui.pushButton_last.hide()
    ui.pushButton_save.show()
    ui.pushButton_cancel.show()
    unlockForm()


def editRecord():
    ui.pushButton_edit.hide()
    ui.pushButton_delete.hide()
    ui.pushButton_add.hide()
    ui.pushButton_first.hide()
    ui.pushButton_previous.hide()
    ui.pushButton_next.hide()
    ui.pushButton_last.hide()
    ui.pushButton_save.hide()
    ui.pushButton_cancel.show()
    ui.pushButton_update.show()
    unlockForm()


def updateRecord():
    try:
        if ui.lineEdit_name.text() and ui.lineEdit_login.text() and ui.lineEdit_pwd.text() != "":
            cur.execute("UPDATE usuarios SET user_real_name=%s, login=%s, pwd=%s WHERE cod_usuario=%s",
                        (ui.lineEdit_name.text(), ui.lineEdit_login.text(),
                         ui.lineEdit_pwd.text(), ui.lineEdit_id.text()))
            connection.commit()
            toggleButtonsVisibility()
            QMessageBox.information(None, "Informação:", "Dados atualizados com sucesso!")
            refreshData()
            lockForm()
        else:
            QMessageBox.warning(None, "Atenção:", "Por favor preencha os campos em branco!")
    except Exception as e:
        QMessageBox.critical(None, "Erro:", "Não foi possível atualizar os dados.\n Cheque o servidor. \n " + str(e))


def deleteRecord():
    cur.execute("DELETE FROM usuarios WHERE cod_usuario =" + ui.lineEdit_id.text())
    connection.commit()
    clearAll()
    toggleButtonsVisibility()
    QMessageBox.information(None, "Informação:", "Usuário deletado com sucesso!")
    refreshData()


def refreshData():
    sql1 = "DROP TEMPORARY TABLE users_temp"
    cur.execute(sql1)
    sql2 = "CREATE TEMPORARY TABLE users_temp AS SELECT * FROM users_view ORDER BY name"
    cur.execute(sql2)
    ShowFirst()


def cancelAll():
    ShowFirst()
    ui.pushButton_edit.show()
    ui.pushButton_delete.show()
    ui.pushButton_add.show()
    ui.pushButton_first.show()
    ui.pushButton_previous.show()
    ui.pushButton_next.show()
    ui.pushButton_last.show()
    ui.pushButton_save.hide()
    ui.pushButton_cancel.hide()
    ui.pushButton_update.hide()


def toggleButtonsVisibility():
    ui.pushButton_add.show()
    ui.pushButton_delete.show()
    ui.pushButton_edit.show()
    ui.pushButton_first.show()
    ui.pushButton_previous.show()
    ui.pushButton_next.show()
    ui.pushButton_last.show()
    ui.pushButton_save.hide()
    ui.pushButton_save.hide()
    ui.pushButton_cancel.hide()
    ui.pushButton_update.hide()


def lockForm():
    for fields in Dialog.findChildren(QtWidgets.QLineEdit):
        fields.setReadOnly(True)


def unlockForm():
    for fields in Dialog.findChildren(QtWidgets.QLineEdit):
        fields.setReadOnly(False)


def clearAll():
    for fields in Dialog.findChildren(QtWidgets.QLineEdit):
        fields.clear()


def saveRecord():
    try:
        if ui.lineEdit_name.text() and ui.lineEdit_login.text() and ui.lineEdit_pwd.text() != "":
            cur.execute('INSERT INTO usuarios (user_real_name, login, pwd, data_cadastro) VALUES(%s, %s, %s, %s)',
                        (ui.lineEdit_name.text(), ui.lineEdit_login.text(), ui.lineEdit_pwd.text(), datetime.today()))
            connection.commit()
            clearAll()
            toggleButtonsVisibility()
            QMessageBox.information(None, "Informação:", "Dados adicionados com sucesso!")
            refreshData()
            lockForm()
        else:
            QMessageBox.warning(None, "Atenção:", "Por favor preencha os campos em branco!")
    except Exception as e:
        QMessageBox.critical(None, "Erro:", "Não foi possível inserir os dados.\n Cheque o servidor. \n " + str(e))


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(Dialog.exec_())



RE: Running external Python file as a subwindow - ndc85430 - Aug-04-2021

You haven't shown any code, so it's literally impossible to help further. Of course I'm not saying each single module needs to contain a single class - perhaps there are more in there. No-one can suggest anything without seeing any code. Have you been through a Python tutorial to understand classes? If you're an experienced C# programmer, this shouldn't be too hard.


RE: Running external Python file as a subwindow - JayCee - Aug-04-2021

I forgot to insert the code, but I edited the reply. It's there now.


RE: Running external Python file as a subwindow - Axel_Erfurt - Aug-04-2021

An Example for showing a second window

run win.py

win.py

from PyQt5.QtWidgets import QMainWindow, QApplication, QAction
from PyQt5.QtGui import QIcon
import second_win

class MainWin(QMainWindow):
    def __init__(self, parent = None):
        super(MainWin, self).__init__(parent)
        self.setupUI()
        
    def setupUI(self):
        self.setGeometry(0, 0, 600, 400)
        self.file_tool_bar = self.addToolBar("File")
        self.my_action = QAction(QIcon.fromTheme("folder"), "", triggered = self.show_second_win)
        self.file_tool_bar.addAction(self.my_action)
        
    def show_second_win(self):
        print("open second win")
        self.sw = second_win.SecondWin()
        self.sw.show()


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    win = MainWin()
    win.setWindowTitle("Main Window")
    win.show()

    sys.exit(app.exec_())
second_win.py

from PyQt5.QtWidgets import QMainWindow, QApplication

class SecondWin(QMainWindow):
    def __init__(self, parent = None):
        super(SecondWin, self).__init__(parent)
        self.setupUI()
        
    def setupUI(self):
        self.setGeometry(100, 100, 400, 300)
        self.setWindowTitle("Second Window")