There are lots of widgets in the original code and that is why I need to open the file in the main window. Therefore, I need to pass a dataframe (data_df) that comes from a csv file open in the main menu (main class) to 'MyApp' class. I will use the dataframe (input_df) to perform calculations down the road.
How to pass the data from main class to MyApp class?
# Import dependencies
from PyQt5.QtWidgets import (QWidget, QApplication, QTableWidget, QTableWidgetItem, QHBoxLayout, QVBoxLayout, QHeaderView, QPushButton, QCheckBox,
QLabel, QFileDialog, QMainWindow, QAction, QLineEdit, QMessageBox, QComboBox, QSizePolicy)
from PyQt5.Qt import Qt, QPen, QFont
from PyQt5.QtGui import *
from PyQt5.QtChart import QChart, QChartView, QLineSeries, QCategoryAxis
import sys
import pandas as pd
import math
import csv
# Creates a QApplication instance
class MyApp(QWidget):
def __init__(self):
super().__init__()
# Creates layout object
self.layout = QHBoxLayout()
# Create push buttons
self.buttonCalc = QPushButton('Calculate')
self.layout.addWidget(self.buttonCalc)
# Connect button to function
self.buttonCalc.clicked.connect(self.calculate)
def displayInfo(self):
self.show()
# Create a Model to handle the calculator's operation
def calculate(self):
# get dataframe
input_df = df
# Create a subclass of QMainWindow to setup the main GUI
class MainWindow(QMainWindow):
def __init__(self, w):
super().__init__()
self.setWindowTitle('My code')
# for icon, uncomment line below
#self.setWindowIcon(QIcon(r'c:\image.png'))
self.resize(1200, 1200)
self.myApp = MyApp()
self.menuBar = self.menuBar()
self.fileMenu = self.menuBar.addMenu('File')
# import data
importAction = QAction('Open csv File', self)
importAction.setShortcut('Ctrl+O')
importAction.triggered.connect(self.openSeries)
# exit action
exitAction = QAction('Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(lambda: app.quit())
self.fileMenu.addAction(importAction)
self.fileMenu.addAction(exitAction)
self.setCentralWidget(w)
def openSeries(self):
self.filePath = QFileDialog.getOpenFileName(self, 'Open data series csv file', 'C:\', 'CSV(*.csv)')
if self.filePath != ('', ''):
file_data = self.filePath[0]
data_df = pd.read_csv(file_data, encoding='ISO-8859-1')
# I need to pass this dataframe to MyApp class
return data_df
def passInformation(self):
self.myApp.input_df
if __name__ =='__main__':
app = QApplication(sys.argv)
w = MyApp()
window = MainWindow(w)
window.show()
try:
sys.exit(app.exec())
except SystemExit:
print('Closing window...')
You can pass the data from one another through the __init__ method using something like this on your main window class:
class MainWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.init_ui()
def goToOtherWindow(self, variable):
self.window = OtherWindow(variable)
self.window.show()
self.close()
On OtherWindow class:
class OtherWindow(QtWidgets.QWidget):
def __init__(self, variable, parent=None):
super(OtherWindow, self).__init__(parent)
self.variable = variable
self.init_ui()
Of course, you have to adapt this function to your specific case.
Related
I am using the code below. Mainwindow's state is preserved but qtreeviw's is not.
import sys
from PyQt5.QtCore import QSettings, QByteArray
from PyQt5.QtWidgets import QApplication, QTreeView, QFileSystemModel, QVBoxLayout, QWidget
from PyQt5 import QtCore
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.tree = QTreeView()
self.settings = QSettings('testorg', 'testapp')
try:
self.tree.header().restoreState(self.settings.value("estado_header"))
self.resize(self.settings.value('window size'))
self.move(self.settings.value('window position'))
except:
pass
self.model = QFileSystemModel()
self.model.setRootPath(r"C:\Users\dan-s>")
self.tree.setModel(self.model)
#self.tree.header().restoreState(self.settings.value("estado_header"))
#self.tree.collapseAll()
layout = QVBoxLayout()
layout.addWidget(self.tree)
self.setLayout(layout)
def closeEvent(self, event):
self.settings.setValue('window size', self.size())
self.settings.setValue('window position', self.pos())
state = self.tree.header().saveState()
self.settings.setValue('estado_header', state)
super().closeEvent(event)
app = QApplication(sys.argv)
demo = MyApp()
demo.show()
sys.exit(app.exec_())
I've tried other ways but I can't solve it.
I'm trying to integrate QFontComboBox within Qmenu.
I try to make two things happen when selecting a particular font from the menu:
The Qmenu will close.
print the selected font.
from PyQt5.QtCore import QObject
from PyQt5.QtGui import QIcon, QFont, QCursor
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QFontComboBox, QWidgetAction, QMenu, QPushButton
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Pyside2 FontCombo Box")
self.setGeometry(300,200,300,250)
self.setFontBox()
self.setIcon()
self.show()
def setIcon(self):
appIcon = QIcon("icon.png")
self.setWindowIcon(appIcon)
def setFontBox(self):
self.font_button = QPushButton(self)
self.font_button.setFixedWidth(300)
self.font_button.clicked.connect(lambda: self.setFontmenu())
vbox = QVBoxLayout()
vbox.addWidget(self.font_button)
self.setLayout(vbox)
def setFontmenu(self):
font_menu = QMenu()
font_submenu = QFontComboBox()
font_submenu.setCurrentFont(QFont("Arial"))
objectTest = QObject()
widget = QWidgetAction(objectTest)
widget.setDefaultWidget(font_submenu)
font_menu.addAction(widget)
font_menu.exec_(QCursor.pos())
menu = font_menu
menu.addSeparator()
font_submenu.showPopup()
font_submenu.setFocus()
font_submenu.currentFontChanged.connect(self._changed)
def _changed(self):
font = self.currentFont().family()
print(font)
return
myapp = QApplication(sys.argv)
window = Window()
myapp.exec_()
sys.exit()
I have a simple application where the back and forward buttons are enabled/disabled based on the history of the visited web pages. For this, I have found the canGoForward and canGoBack functions
of the QWebEngineHistory. However, the functions return True only after there are at least three items in the history. Normally, browsers work right after visiting the second different page.
Is this supposed to be working like that? I there any way to change it to the 2 web pages? I have looked at the QWebEngineSettings, but there is nothing related to this.
Here is a working example:
#!/usr/bin/python
import sys
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (QApplication, QLineEdit, QMainWindow,
QPushButton, QToolBar)
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineView
class Example(QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.toolBar = QToolBar(self)
self.addToolBar(self.toolBar)
self.backBtn = QPushButton(self)
self.backBtn.setEnabled(False)
self.backBtn.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/left-32.png'))
# self.backBtn.setIcon(QIcon('stock_left.png'))
self.backBtn.clicked.connect(self.back)
self.toolBar.addWidget(self.backBtn)
self.forBtn = QPushButton(self)
self.forBtn.setEnabled(False)
# self.forBtn.setIcon(QIcon('stock_right.png'))
self.forBtn.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/right-32.png'))
self.forBtn.clicked.connect(self.forward)
self.toolBar.addWidget(self.forBtn)
self.address = QLineEdit(self)
self.address.returnPressed.connect(self.load)
self.toolBar.addWidget(self.address)
self.webEngineView = QWebEngineView(self)
self.setCentralWidget(self.webEngineView)
self.webEngineView.page().urlChanged.connect(self.onLoadFinished)
print(self.webEngineView.history().backItem().url())
print(self.webEngineView.history().forwardItem().url())
self.setGeometry(300, 300, 500, 400)
self.setWindowTitle('QWebEnginePage')
self.show()
# self.webEngineView.page().urlChanged.connect(self.urlChanged)
def onLoadFinished(self):
print(dir(self.webEngineView.history()))
print('load finished')
# print(self.webEngineView.history().backItem().url())
# print(self.webEngineView.history().forwardItem().url())
# print(self.webEngineView.history().backItem())
# print(self.webEngineView.history().forwardItem())
# print(self.webEngineView.history().count())
# print(self.webEngineView.history().items())
# print(self.webEngineView.history().canGoForward())
# print(self.webEngineView.history().canGoBack())
if self.webEngineView.history().canGoBack():
self.backBtn.setEnabled(True)
else:
self.backBtn.setEnabled(False)
if self.webEngineView.history().canGoForward():
self.forBtn.setEnabled(True)
else:
self.forBtn.setEnabled(False)
def load(self):
url = QUrl.fromUserInput(self.address.text())
if url.isValid():
self.webEngineView.load(url)
def back(self):
self.webEngineView.page().triggerAction(QWebEnginePage.Back)
def forward(self):
self.webEngineView.page().triggerAction(QWebEnginePage.Forward)
def urlChanged(self, url):
self.address.setText(url.toString())
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I need to select the default file that appears in a combobox from a directory listing of files. With a normal combobox, it is easy enough to find the index of the value you want using .findText, but this does not appear to work for QFileSystemModel comboboxes, possibly due to the way the list of options does not populate until the directory listing can be resourced.
Here is what I have tried:
import sys
import collections
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QLabel, QGridLayout, QWidget, QComboBox
from PyQt5.QtCore import QSize, QRect
class ComboWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setMinimumSize(QSize(640, 140))
self.setWindowTitle("Combobox example")
centralWidget = QWidget(self)
self.setCentralWidget(centralWidget)
# Create combobox and add items.
self.fsm = QtWidgets.QFileSystemModel()
self.fsm.setNameFilters(["*.txt"])
self.configComboBox = QtWidgets.QComboBox(self)
self.configComboBox.setGeometry(QRect(40, 40, 491, 31))
self.configComboBox.setObjectName(("comboBox"))
self.configComboBox.setModel(self.fsm)
self.fsm.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Files)
# "text_files" is a subdir of current dir with files
# example1.txt, example2.txt, example3.txt
self.configComboBox.setRootModelIndex(self.fsm.setRootPath("text_files"))
# V V This section does not work V V
index = self.configComboBox.findText(MainConfig.settings["default_txt_file"])
self.configComboBox.setCurrentIndex(index)
class MainConfig:
settings = collections.OrderedDict()
#staticmethod
def createDefaultConfig(name):
MainConfig.settings["default_txt_file"] = "example3.txt"
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = ComboWindow()
mainWin.show()
sys.exit( app.exec_() )
As I indicated in this answer, the QFileSystemModel is loaded asynchronously in a new thread so you must use the directoryLoaded signal to know when the information is finished loading:
import collections
import os
import sys
from PyQt5.QtWidgets import (
QApplication,
QComboBox,
QFileSystemModel,
QMainWindow,
QWidget,
)
from PyQt5.QtCore import pyqtSlot, QDir, QRect, QSize
class ComboWindow(QMainWindow):
def __init__(self, parent=None):
super(ComboWindow, self).__init__(parent=None)
self.setMinimumSize(QSize(640, 140))
self.setWindowTitle("Combobox example")
centralWidget = QWidget(self)
self.setCentralWidget(centralWidget)
# Create combobox and add items.
self.fsm = QFileSystemModel()
self.fsm.setNameFilters(["*.txt"])
self.configComboBox = QComboBox(self)
self.configComboBox.setGeometry(QRect(40, 40, 491, 31))
self.configComboBox.setObjectName(("comboBox"))
self.configComboBox.setModel(self.fsm)
self.fsm.setFilter(QDir.NoDotAndDotDot | QDir.Files)
self.fsm.directoryLoaded.connect(self.on_directoryLoaded)
current_dir = os.path.dirname(os.path.realpath(__file__))
dir_path = os.path.join(current_dir, "text_files")
self.configComboBox.setRootModelIndex(self.fsm.setRootPath(dir_path))
#pyqtSlot(str)
def on_directoryLoaded(self, path):
index = self.configComboBox.findText(MainConfig.settings["default_txt_file"])
self.configComboBox.setCurrentIndex(index)
class MainConfig:
settings = collections.OrderedDict()
#staticmethod
def createDefaultConfig(name):
MainConfig.settings["default_txt_file"] = name
if __name__ == "__main__":
MainConfig.createDefaultConfig("example3.txt")
app = QApplication(sys.argv)
mainWin = ComboWindow()
mainWin.show()
sys.exit(app.exec_())
I am stack trying to include MenuBar from separate file and trying to connect with function
I include some code that I have the same problem
foo.py
from PyQt5.QtWidgets import *
from PyQt5.uic import loadUiType
import os
import sys
from foomenu import menu
FROM_MAIN, _ = loadUiType(os.path.join(os.path.dirname(__file__), "SalesGui.ui"))
class Main(QMainWindow, FROM_MAIN):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
self.MyMenu = menu(self)
self.MyMenu.NewProduct.triggered.connect(self.NewProduct())
def NewProduct(self):
print("foo")
def main():
app = QApplication(sys.argv)
window = Main()
window.show()
app.exec_()
if __name__ == '__main__':
try:
main()
except Exception as why:
print(why)
and foomenu.py
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QAction, QMenu
def menu(self):
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('FooMenu')
NewProduct = QAction(QIcon('icons/exit.png'), 'Foo', self)
NewProduct.setShortcut('Ctrl+Q')
NewProduct.setStatusTip('FooAction')
fileMenu.addAction(NewProduct)
When Trying to connect the "NewProduct" button with "New Product" function I get the following error
'NoneType' object has no attribute 'NewProduct'
Try it:
import os
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QAction, QMenu
#from PyQt5.uic import loadUiType
#from foomenu import menu
#FROM_MAIN, _ = loadUiType(os.path.join(os.path.dirname(__file__), "SalesGui.ui"))
def menu(self):
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('FooMenu')
self.NewProduct = QAction(QIcon('exit.png'), 'Foo', self) # 'icons/exit.png' # + self
self.NewProduct.setShortcut('Ctrl+Q')
self.NewProduct.setStatusTip('FooAction')
fileMenu.addAction(self.NewProduct)
return self.NewProduct # +++
class Main(QMainWindow):#, FROM_MAIN):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
# self.setupUi(self)
self.MyMenu = menu(self)
# self.MyMenu.NewProduct.triggered.connect(self.funcNewProduct) # - ()
self.MyMenu.triggered.connect(self.funcNewProduct) # +
def funcNewProduct(self):
print("foo")
qApp.quit()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Main()
window.show()
app.exec_()
It is much more elegant to subclass and setup the menubar in this another python file then import and instance this class in your file that holds the Main class.
In the MyMenu class you can binding the signal a socket locally that can provide from here the sender object for the parent class.
BTW you can iterate over the action object of the menubar/menus but it is much more harder to maintain and control then the explicit describe where to connect the potential different actions.
Menu.py:
class MyMenu(QMenuBar):
new_product_clicked = Signal(object)
def __init__(self, parent=None):
super(MyMenu, self).__init__(parent)
file_menu = QMenu("File menu", self)
new_product_action = QAction('Foo', self)
new_product_action.setShortcut('Ctrl+Q')
new_product_action.setStatusTip('FooAction')
new_product_action.triggered.connect(self.new_product_clicked)
file_menu.addAction(new_product_action)
self.addMenu(file_menu)
def new_product_clicked(self):
""" Call a method from the parent class. """
self.new_product_clicked.emit(self.sender())
Main.py:
from Menu import MyMenu
class Main(QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
my_menu = MyMenu(self)
self.setMenuBar(my_menu)
self.my_menu.new_product_clicked.connect(self.product_clicked)
def product_clicked(self, action):
""" Socket for the clicked action """
clicked_action = action
print clicked_action.text()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Main()
window.show()
app.exec_()