Embedding PyQt script in c++
-
Hi.
I was wondering if there is a way to execute a Qt python script from c++
I have tried using QProcess which told me the script was executed but neither a window was open or any other sign the python code really executedvoid MainMenu::on_LogIn_PB_clicked() { QProcess process; process.start("/usr/bin/python3", QStringList() << "/Users/boyankiovtorov/PycharmProjects/pythonProject/script/crypto.py"); if (!process.waitForFinished()) { qDebug() << "Error: " << process.errorString(); } else { qDebug() << "Process finished successfully."; } }
The script is the following if it helps with anything
from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6.QtCore import QTimer import cryptocompare class Ui_Crypto(object): def setupUi(self, Crypto): Crypto.setObjectName("Crypto") Crypto.resize(1280, 720) self.label = QtWidgets.QLabel(parent=Crypto) self.label.setGeometry(QtCore.QRect(70, 50, 51, 51)) self.label.setObjectName("label") self.comboBox = QtWidgets.QComboBox(parent=Crypto) self.comboBox.setGeometry(QtCore.QRect(120, 70, 171, 24)) self.comboBox.setObjectName("comboBox") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.price_LA = QtWidgets.QLabel(parent=Crypto) self.price_LA.setGeometry(QtCore.QRect(80, 190, 251, 16)) self.price_LA.setText("") self.price_LA.setObjectName("price_LA") self.retranslateUi(Crypto) # Set up QTimer self.timer = QTimer(Crypto) self.timer.timeout.connect(self.update_price) self.timer.start(2000) # Update every 2000 milliseconds (2 seconds) QtCore.QMetaObject.connectSlotsByName(Crypto) def retranslateUi(self, Crypto): _translate = QtCore.QCoreApplication.translate Crypto.setWindowTitle(_translate("Crypto", "Form")) self.label.setText(_translate("Crypto", "Crypto:")) self.comboBox.setItemText(0, _translate("Crypto", "BTC")) self.comboBox.setItemText(1, _translate("Crypto", "ETH")) self.comboBox.setItemText(2, _translate("Crypto", "BNB")) self.comboBox.setItemText(3, _translate("Crypto", "BCH")) self.comboBox.setItemText(4, _translate("Crypto", "Doge")) def update_price(self): # Fetch the price and update the label text selected_crypto = self.comboBox.currentText() price = cryptocompare.get_price(selected_crypto, currency="USD") self.price_LA.setText(str(price)) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) Crypto = QtWidgets.QWidget() ui = Ui_Crypto() ui.setupUi(Crypto) Crypto.show() sys.exit(app.exec())
Thanks!
-
Hi.
I was wondering if there is a way to execute a Qt python script from c++
I have tried using QProcess which told me the script was executed but neither a window was open or any other sign the python code really executedvoid MainMenu::on_LogIn_PB_clicked() { QProcess process; process.start("/usr/bin/python3", QStringList() << "/Users/boyankiovtorov/PycharmProjects/pythonProject/script/crypto.py"); if (!process.waitForFinished()) { qDebug() << "Error: " << process.errorString(); } else { qDebug() << "Process finished successfully."; } }
The script is the following if it helps with anything
from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6.QtCore import QTimer import cryptocompare class Ui_Crypto(object): def setupUi(self, Crypto): Crypto.setObjectName("Crypto") Crypto.resize(1280, 720) self.label = QtWidgets.QLabel(parent=Crypto) self.label.setGeometry(QtCore.QRect(70, 50, 51, 51)) self.label.setObjectName("label") self.comboBox = QtWidgets.QComboBox(parent=Crypto) self.comboBox.setGeometry(QtCore.QRect(120, 70, 171, 24)) self.comboBox.setObjectName("comboBox") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.price_LA = QtWidgets.QLabel(parent=Crypto) self.price_LA.setGeometry(QtCore.QRect(80, 190, 251, 16)) self.price_LA.setText("") self.price_LA.setObjectName("price_LA") self.retranslateUi(Crypto) # Set up QTimer self.timer = QTimer(Crypto) self.timer.timeout.connect(self.update_price) self.timer.start(2000) # Update every 2000 milliseconds (2 seconds) QtCore.QMetaObject.connectSlotsByName(Crypto) def retranslateUi(self, Crypto): _translate = QtCore.QCoreApplication.translate Crypto.setWindowTitle(_translate("Crypto", "Form")) self.label.setText(_translate("Crypto", "Crypto:")) self.comboBox.setItemText(0, _translate("Crypto", "BTC")) self.comboBox.setItemText(1, _translate("Crypto", "ETH")) self.comboBox.setItemText(2, _translate("Crypto", "BNB")) self.comboBox.setItemText(3, _translate("Crypto", "BCH")) self.comboBox.setItemText(4, _translate("Crypto", "Doge")) def update_price(self): # Fetch the price and update the label text selected_crypto = self.comboBox.currentText() price = cryptocompare.get_price(selected_crypto, currency="USD") self.price_LA.setText(str(price)) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) Crypto = QtWidgets.QWidget() ui = Ui_Crypto() ui.setupUi(Crypto) Crypto.show() sys.exit(app.exec())
Thanks!
@DeadSo0ul
There is no obvious why this should not work. Put some kind of debugging statements into the Python script so you know how far it got, also probably a slot in the C++ on theerrorOccurred
signal forQProcess
and/or print out anything the sub-process might print to stdout/err.As it stands are you saying it shows nothing and then 30 seconds later prints
Error: ...
? -
@DeadSo0ul
There is no obvious why this should not work. Put some kind of debugging statements into the Python script so you know how far it got, also probably a slot in the C++ on theerrorOccurred
signal forQProcess
and/or print out anything the sub-process might print to stdout/err.As it stands are you saying it shows nothing and then 30 seconds later prints
Error: ...
?Hi @JonB
I did some debugging and figured out the program stops from the begininng when importingprint("importing") from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6.QtCore import QTimer import cryptocompare print("imports successful")
My updated c++ code
void MainMenu::on_LogIn_PB_clicked() { QProcess process; process.start("/usr/bin/python3", QStringList() << "/Users/boyankiovtorov/PycharmProjects/pythonProject/script/crypto.py"); if (!process.waitForFinished()) { qDebug() << "Error: " << process.errorString(); } else { qDebug() << "Process finished successfully."; // Read standard output of the process QByteArray outputData = process.readAllStandardOutput(); QString outputString = QString::fromUtf8(outputData); qDebug() << "Output:" << outputString; } }
output
Process finished successfully. Output: "importing\n"
No error is displaying no matter how much I wait since "finished successfully" has been displayed
-
Hi @JonB
I did some debugging and figured out the program stops from the begininng when importingprint("importing") from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6.QtCore import QTimer import cryptocompare print("imports successful")
My updated c++ code
void MainMenu::on_LogIn_PB_clicked() { QProcess process; process.start("/usr/bin/python3", QStringList() << "/Users/boyankiovtorov/PycharmProjects/pythonProject/script/crypto.py"); if (!process.waitForFinished()) { qDebug() << "Error: " << process.errorString(); } else { qDebug() << "Process finished successfully."; // Read standard output of the process QByteArray outputData = process.readAllStandardOutput(); QString outputString = QString::fromUtf8(outputData); qDebug() << "Output:" << outputString; } }
output
Process finished successfully. Output: "importing\n"
No error is displaying no matter how much I wait since "finished successfully" has been displayed
@DeadSo0ul said in Embedding PyQt script in c++:
if (!process.waitForFinished()) { qDebug() << "Error: " << process.errorString(); } else { qDebug() << "Process finished successfully."; // Read standard output of the process QByteArray outputData = process.readAllStandardOutput();
The errors types reported by errorString() probably don't include what you're looking for.
More likely, the desired output is written to the standard error file descriptor. Either read it explicitly with QProcess::readAllStandardError(), or set the process channel mode to QProcess::MergedChannels.
-
@DeadSo0ul said in Embedding PyQt script in c++:
if (!process.waitForFinished()) { qDebug() << "Error: " << process.errorString(); } else { qDebug() << "Process finished successfully."; // Read standard output of the process QByteArray outputData = process.readAllStandardOutput();
The errors types reported by errorString() probably don't include what you're looking for.
More likely, the desired output is written to the standard error file descriptor. Either read it explicitly with QProcess::readAllStandardError(), or set the process channel mode to QProcess::MergedChannels.
@jeremy_k
I see the problem now. The script can not find any additional import that has been installed through pip
Error output:Output: "Traceback (most recent call last):\n File \"/Users/boyan/PycharmProjects/pythonProject/script/crypto.py\", line 9, in <module>\n from PyQt6 import QtCore, QtGui, QtWidgets\nModuleNotFoundError: No module named 'PyQt6'\n"
-
@jeremy_k
I see the problem now. The script can not find any additional import that has been installed through pip
Error output:Output: "Traceback (most recent call last):\n File \"/Users/boyan/PycharmProjects/pythonProject/script/crypto.py\", line 9, in <module>\n from PyQt6 import QtCore, QtGui, QtWidgets\nModuleNotFoundError: No module named 'PyQt6'\n"
@DeadSo0ul
A similar question/issue was raised as its own thread very recently, where modules installed via pip are not being found when run as a sub-process from a Qt C== application. I don't know why or how that is happening. Start by examining environment variables, does one of these tell pip where to look and is somehow different from a command line than from a Qt/C++ program?Of course if you normally run the PyQt6 in some kind of Python virtual environment (e.g. like anaconda) you must replicate whatever that requires if you run from your C++ program.
-
@DeadSo0ul
A similar question/issue was raised as its own thread very recently, where modules installed via pip are not being found when run as a sub-process from a Qt C== application. I don't know why or how that is happening. Start by examining environment variables, does one of these tell pip where to look and is somehow different from a command line than from a Qt/C++ program?Of course if you normally run the PyQt6 in some kind of Python virtual environment (e.g. like anaconda) you must replicate whatever that requires if you run from your C++ program.
@JonB
Do you mean telling the qt/c++ application where to look for pip?
I was thinking because when I run the python code from my IDE (PyCharm) the program makes a hidden folder named .venv where pip is located along with the downloaded through pip additional libraries. Is there any way to tell the qt/c++ program "hey here is this pip folder with all its libraries please include them" -
@JonB
Do you mean telling the qt/c++ application where to look for pip?
I was thinking because when I run the python code from my IDE (PyCharm) the program makes a hidden folder named .venv where pip is located along with the downloaded through pip additional libraries. Is there any way to tell the qt/c++ program "hey here is this pip folder with all its libraries please include them"@DeadSo0ul said in Embedding PyQt script in c++:
when I run the python code from my IDE (PyCharm) the program makes a hidden folder named .venv where pip is located along with the downloaded through pip additional libraries.
Then as I wondered might be the case i think this is the reason it runs from PyCharm but not from an external program. Assuming you mean PyCharm has permanently installed pip stuff in its own area then you must tell another program where that is for it to work.
I do not now know the workings of PyCharm and virtual environments/directories. First things first: you must get your Python script run not only outside of Qt or Qt Creator but also outside of PyCharm. Have you got that working yet? Once you have it running directly from a terminal with no PyCharm involved then we can look at how to get it running from an external C++ program.
P.S.
It might be/you could Google for environment variablePYTHONPATH
? It might be that all you need is for the directory containing your pip installed stuff to be in that variable for a Python script to find the modules? Also have a look inside PyCharm at what settings/directories it shows you have set up to run with? -
@DeadSo0ul said in Embedding PyQt script in c++:
when I run the python code from my IDE (PyCharm) the program makes a hidden folder named .venv where pip is located along with the downloaded through pip additional libraries.
Then as I wondered might be the case i think this is the reason it runs from PyCharm but not from an external program. Assuming you mean PyCharm has permanently installed pip stuff in its own area then you must tell another program where that is for it to work.
I do not now know the workings of PyCharm and virtual environments/directories. First things first: you must get your Python script run not only outside of Qt or Qt Creator but also outside of PyCharm. Have you got that working yet? Once you have it running directly from a terminal with no PyCharm involved then we can look at how to get it running from an external C++ program.
P.S.
It might be/you could Google for environment variablePYTHONPATH
? It might be that all you need is for the directory containing your pip installed stuff to be in that variable for a Python script to find the modules? Also have a look inside PyCharm at what settings/directories it shows you have set up to run with?@JonB
I did run the python script the same way PyCharm does it (I think)
First I created a virtual environment with the commandpython3 -m venv /Users/boyan/Desktop/python/venv
and ran the virtual environment with the command
source /venv/bin/activate
installed the libraries with
pip install
and ran the script withpython3 file.py
Can't I just tell qt to do these commands for me and will it work?
Thinking now I don't change anything as the script still does not know what or where those libraries are.I will look into environment variable PYTHONPATH now.
-
@JonB
I did run the python script the same way PyCharm does it (I think)
First I created a virtual environment with the commandpython3 -m venv /Users/boyan/Desktop/python/venv
and ran the virtual environment with the command
source /venv/bin/activate
installed the libraries with
pip install
and ran the script withpython3 file.py
Can't I just tell qt to do these commands for me and will it work?
Thinking now I don't change anything as the script still does not know what or where those libraries are.I will look into environment variable PYTHONPATH now.
@JonB
I managed to make the python script work without any virtual environment.I just installed pip with the commands
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py
Now I can just pre-install the libraries I need and the script will run with the simple
python3 file.py
The question now is how to make qt use those pre-installed libraries
-
@JonB
I managed to make the python script work without any virtual environment.I just installed pip with the commands
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py
Now I can just pre-install the libraries I need and the script will run with the simple
python3 file.py
The question now is how to make qt use those pre-installed libraries
@DeadSo0ul
Well, Qt orQProcess
does not use any libraries nor run any script. That is down to yourpython3
process. You need to find out (I don't know) how that locates the imports/libraries/directory or whatever. I suggested you perhaps look at or Google thePYTHONPATH
environment variable? -
Hi,
From old memories, look at the content of the activate script and configure your QProcess in a similar way. You likely have to modify the PATH environment variable as well as PYTHONPATH before starting your QProcess.
-
In addition to using or replicating <venv>/bin/activate or <venv>/scripts/activate, the python interpreter in <venv>/bin/python knows about the virtual environment.
For example:
$ ~/venv/bin/python -c "import sys; print('\n'.join(sys.path))" /Library/Frameworks/Python.framework/Versions/3.8/lib/python38.zip /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/lib-dynload /Users/jeremy_k/venv/lib/python3.8/site-packages
-
In addition to using or replicating <venv>/bin/activate or <venv>/scripts/activate, the python interpreter in <venv>/bin/python knows about the virtual environment.
For example:
$ ~/venv/bin/python -c "import sys; print('\n'.join(sys.path))" /Library/Frameworks/Python.framework/Versions/3.8/lib/python38.zip /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/lib-dynload /Users/jeremy_k/venv/lib/python3.8/site-packages
@jeremy_k
Hi again
Thanks everyone for helping me. I did manage to make it work by installing pip and setting the correct python executable as a parameter to the QProcess::start() function. My mistake was linking the wrong python (specifically, Microsoft's Python)For anyone wondering here is my working code
QProcess process; process.start("C:/Users/boyan/AppData/Local/Programs/Python/Python312/python.exe", QStringList() << "C:/Users/boyan/Desktop/sd.py"); if (!process.waitForFinished()) { qDebug() << "Error: " << process.errorString(); } else { qDebug() << "Process finished successfully."; // Read standard output of the process QByteArray outputData = process.readAllStandardError(); QString outputString = QString::fromUtf8(outputData); qDebug() << "Output:" << outputString; }
-