I want to make GUI application which asks the user for the champion they want to check and then their role (e.g Middle, Jungle, Top, ADC, Support) and then it will display the "Most Frequent Runes" and some other data on the website. I believe PyQt5 would be the best python GUI for this as it has embedded webpages but please suggest alternatives.
With this code:
from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtWidgets import QApplication
import sys
#champion = input("What champion would you like to check? ")
champions = "Katarina"
#role = input("What role are you playing (Middle, Jungle, Top, ADC, Support)? ")
roles = "Middle"
URL = f"https://champion.gg/champion/{champions.capitalize()}/{roles.capitalize()}?"
app = QApplication(sys.argv)
web = QWebEngineView()
web.load(QUrl(URL))
web.show()
sys.exit(app.exec_())
It displays the whole webpage but I only want the "Most frequent Runes" section shown like it is like this:
and then hold it as a variable (QLabel?) that can then be placed wherever I want it. I have tried to look over how to do this but i couldn't find a solution. I would rather have done it using tkinter but it seems that isn't possible (or as far as I have been able to gather - if their is a way please explain as much as you can how).
I tried scraping the website using bs4 and requests with this code:
from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import *
from bs4 import BeautifulSoup
import requests
import time
import sys
#champion = input("What champion would you like to check? ")
champions = "Katarina"
#role = input("What role are you playing (Middle, Jungle, Top, ADC, Support)? ")
roles = "Middle"
URL = f"https://champion.gg/champion/{champions.capitalize()}/{roles.capitalize()}?"
app = QApplication(sys.argv)
page = requests.get('https://champion.gg/champion/Katarina/Middle?')
soup = BeautifulSoup(page.text, 'lxml')
championData = soup.find('div', 'summoner-text')
window = QWidget()
window.setWindowTitle("League of Legends helper")
window.setGeometry(100, 100, 550, 250)
runes = QLabel(championData, parent=window)
but it just produces errors which I haven't fully been able to understand.
Error:
Traceback (most recent call last):
File "(FILEPATH)", line 32, in <module>
runes = QLabel(championData, parent=window)
TypeError: arguments did not match any overloaded call:
QLabel(parent: QWidget = None, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags()): argument 1 has unexpected type 'Tag'
QLabel(str, parent: QWidget = None, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags()): argument 1 has unexpected type 'Tag'
BeautifulSoup's is an HTML parser so each node of the DOM has a wrapper that allows access to its properties, so championData is not a string causing the error.
Even so, you would extract the HTML from the node, it would be useless because the "requests" library does not obtain the HTML generated dynamically by javascript, in addition, the styles would not be kept as they depend on other files.
A possible solution for this case is to extract the HTML from that node and place it in the same document using javascript:
import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
def main(*, champions, roles):
url = f"https://champion.gg/champion/{champions.capitalize()}/{roles.capitalize()}?"
app = QtWidgets.QApplication(sys.argv)
web = QtWebEngineWidgets.QWebEngineView()
web.resize(640, 480)
progress_dialog = QtWidgets.QProgressDialog()
progress_dialog.setLabelText(
"""""<p><span style=" font-size:20pt; font-weight:600;">Loadding ...</span></p>"""
)
progress_dialog.resize(640, 480)
progress_dialog.show()
web.loadProgress.connect(progress_dialog.setValue)
button = progress_dialog.findChild(QtWidgets.QPushButton)
if button is not None:
button.clicked.connect(QtCore.QCoreApplication.quit)
def on_load_finished():
codes = [
"""var iterator = document.evaluate("/html[1]/body[1]/div[1]/div[2]/div[3]/div[2]/div[2]/div[1]/div[1]/div[2]/div[1]/div[3]", document, null, XPathResult.ANY_TYPE, null)""",
"""var e = iterator.iterateNext() """,
"""document.body.innerHTML = e.innerHTML""",
"""document.body.children[0].style.marginTop = "10px" """,
]
for code in codes:
web.page().runJavaScript(code)
web.move(progress_dialog.pos())
web.show()
progress_dialog.close()
web.loadFinished.connect(on_load_finished)
web.load(QtCore.QUrl(url))
sys.exit(app.exec_())
if __name__ == "__main__":
main(champions="Katarina", roles="Middle")
Update:
import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self._champion_le = QtWidgets.QLineEdit(placeholderText=self.tr("champion"))
self._role_cb = QtWidgets.QComboBox()
self._web = QtWebEngineWidgets.QWebEngineView()
self._search_btn = QtWidgets.QPushButton(self.tr("Search"))
self._stacked = QtWidgets.QStackedWidget()
self._progress_bar = QtWidgets.QProgressBar()
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QGridLayout(central_widget)
lay.addWidget(self._champion_le, 0, 0)
lay.addWidget(self._role_cb, 0, 1)
lay.addWidget(self._search_btn, 0, 2)
lay.addWidget(self._stacked, 1, 0, 1, 3)
container = QtWidgets.QWidget()
lay = QtWidgets.QVBoxLayout(container)
lay.addWidget(
QtWidgets.QLabel(
self.tr(
"""<p><span style="font-size:20pt; font-weight:600;">Loadding ...</span></p>"""
)
)
)
lay.addWidget(self._progress_bar)
self._stacked.addWidget(QtWidgets.QWidget())
self._stacked.addWidget(container)
self._stacked.addWidget(self._web)
self._role_cb.addItems(["Top", "Jungle", "Middle", "ADC", "Support"])
self._search_btn.clicked.connect(self.on_clicked)
self._web.loadFinished.connect(self.on_load_finished)
self._web.loadProgress.connect(self._progress_bar.setValue)
self.resize(640, 480)
self._champion_le.setText("Aatrox")
self._role_cb.setCurrentText("Top")
#QtCore.pyqtSlot()
def on_clicked(self):
champion = self._champion_le.text()
role = self._role_cb.currentText()
if champion:
self._stacked.setCurrentIndex(1)
self.change(champion, role)
def change(self, champion, role):
url = f"https://champion.gg/champion/{champion.capitalize()}/{role}?"
self._web.load(QtCore.QUrl(url))
#QtCore.pyqtSlot(bool)
def on_load_finished(self, ok):
if ok:
codes = [
"""var iterator = document.evaluate("/html[1]/body[1]/div[1]/div[2]/div[3]/div[2]/div[2]/div[1]/div[1]/div[2]/div[1]/div[3]", document, null, XPathResult.ANY_TYPE, null)""",
"""var e = iterator.iterateNext() """,
"""document.body.innerHTML = e.innerHTML""",
"""document.body.children[0].style.marginTop = "10px" """,
]
for code in codes:
self._web.page().runJavaScript(code)
self._stacked.setCurrentIndex(2)
def main():
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Related
So i have a problem writing what i have as list in a python code into my Qwidget , what i want is : as i have a list of tweets , when i click on the button i want my code to write what i have in a list in the Qwidget i don't know what to use for the writing part , i thought of using QPlainTextEdit which i think is not right , can you give me an idea of what to use and how ?
here is my code
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
import gettweet
app = QApplication.instance()
if not app:
app = QApplication(sys.argv)
widget = QWidget()
get = QPushButton(widget)
get.setText("Get tweet")
get.move(64,32)
widget.setGeometry(50,50,800,600)
widget.setWindowTitle("Sentiments tweets")
QtWidgets.QPlainTextEdit(widget).setGeometry(300,0 , 500,600)
def window() :
get.clicked.connect(button1_clicked)
widget.show()
app.exec_()
def button1_clicked() :
tweets = gettweet.get()
for i in tweets :
pass
if __name__ == '__main__':
window()
i do not know if you want it like this but i made the application put the items that are in the list to the QPlainTextEdit.
you should edit and fix the code to make it like what you want because i edited it.
from re import I
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
app = QApplication.instance()
if not app:
app = QApplication(sys.argv)
widget = QWidget()
def button1_clicked() :
tweets = ["My love is mohammed almalki","i love mohammed almalki very much"]
for i in tweets :
MyQPlainTextEdit.setPlainText(i)
get = QPushButton(widget)
get.setText("Get tweet")
get.move(64,32)
widget.setGeometry(50,50,800,600)
widget.setWindowTitle("Sentiments tweets")
MyQPlainTextEdit = QtWidgets.QPlainTextEdit(widget)
MyQPlainTextEdit.setGeometry(300,0 , 500,600)
def window() :
get.clicked.connect(button1_clicked)
widget.show()
app.exec_()
if __name__ == '__main__':
window()
and i will give you an idea
you can create a container and put in it a lot of QPlainTextEdit like you have of tweets for example you have 10 tweets and you want to show them you can make it like this:
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
class ForExample:
Tweets = ["Oh i do not know if i will meet mohammed almalki or not i love him very much",
"One of my favorite people is mohammed almalki",
"OMG did you meet Mohammed?? oh my god i think that is your best day right?"]
def __init__(self):
self.Application = QtWidgets.QApplication([])
self.Window = QtWidgets.QWidget()
self.Window.resize(800,500)
self.WindowLayout = QtWidgets.QGridLayout()
self.ScrollArea = QtWidgets.QScrollArea()
self.ScrollArea.setWidgetResizable(True)
self.GroupBox = QtWidgets.QGroupBox()
self.GroupBoxLayout = QtWidgets.QGridLayout()
self.GroupBox.setLayout(self.GroupBoxLayout)
self.ScrollArea.setWidget(self.GroupBox)
def FunctionToDoTheWord():
for i in range(len(self.Tweets)):
self.GroupBoxLayout.addWidget(QtWidgets.QPlainTextEdit(self.Tweets[i]))
self.ButtonToShowTheTweets = QtWidgets.QPushButton("Show Tweets")
self.ButtonToShowTheTweets.clicked.connect(FunctionToDoTheWord)
self.WindowLayout.addWidget(self.ScrollArea)
self.WindowLayout.addWidget(self.ButtonToShowTheTweets)
self.Window.setLayout(self.WindowLayout)
self.Window.show()
self.Application.exec()
ForExample()
try this and tell me.
I have a Pyqt5 form where the user enters data. This data is sent to another module, where it is processed and returned for display in the form.
Very simplistically it looks like this:
frm.py
import sys
from PyQt5.QtWidgets import *
import mdl
def fnc0(in_val):
mdl.fnc1(in_val)
def fnc2(rezult):
msg.setText(rezult)
app = QApplication(sys.argv)
window = QWidget()
layout = QVBoxLayout()
btn = QPushButton('button')
btn.clicked.connect(lambda: fnc0(5))
layout.addWidget(btn)
msg = QLabel('')
layout.addWidget(msg)
window.setLayout(layout)
window.show()
sys.exit(app.exec_())
mdl.py
import frm
def fnc1(in_val):
out_val = str(in_val*2)
frm.fnc2(out_val)
However, when doing this, I get the error of using circular modules:
AttributeError: partially initialized module 'mdl' has no attribute 'fnc1' (most likely due to a circular import)
Is it possible to process the data sent from the form to another module, and then return the result to the form?
A possible solution is that in a third file we create a logic where we can register functions that receive the result and a function that invokes those functions:
core.py
_funct = []
def register_writer(func):
_funct.append(func)
return func
def write(text):
for f in _funct:
f(text)
mdl.py
import core
def fnc1(in_val):
out_val = str(in_val * 2)
core.write(out_val)
frm.py
import sys
from PyQt5.QtWidgets import *
import core
import mdl
#core.register_writer
def fnc2(rezult):
msg.setText(rezult)
app = QApplication(sys.argv)
window = QWidget()
layout = QVBoxLayout()
btn = QPushButton("button")
btn.clicked.connect(lambda: mdl.fnc1(5))
layout.addWidget(btn)
msg = QLabel()
layout.addWidget(msg)
window.setLayout(layout)
window.show()
sys.exit(app.exec_())
The clip below shows dragging QDockWidgets between docking areas by dragging the tabs (not the title bar) - but when I try this with PyQt 5.15.0 it doesn't work, the tabs won't detach. How can I enable this behavior?
What I want:
https://www.screencast.com/t/lv83SoyVUhbd (from https://woboq.com/blog/qdockwidget-changes-in-56.html)
What I get:
https://www.screencast.com/t/bIUj4vLNTF
My code:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
if __name__ == "__main__":
app = QtWidgets.QApplication([])
main = QtWidgets.QMainWindow()
dock1 = QtWidgets.QDockWidget("Blue")
dock2 = QtWidgets.QDockWidget("Green")
dock3 = QtWidgets.QDockWidget("Red")
content1 = QtWidgets.QWidget()
content1.setStyleSheet("background-color:blue;")
content2 = QtWidgets.QWidget()
content2.setStyleSheet("background-color:green;")
content3 = QtWidgets.QWidget()
content3.setStyleSheet("background-color:red;")
dock1.setWidget(content1)
dock2.setWidget(content2)
dock3.setWidget(content3)
dock1.setAllowedAreas(Qt.AllDockWidgetAreas)
dock2.setAllowedAreas(Qt.AllDockWidgetAreas)
dock3.setAllowedAreas(Qt.AllDockWidgetAreas)
main.addDockWidget(Qt.LeftDockWidgetArea, dock1)
main.tabifyDockWidget(dock1, dock2)
main.addDockWidget(Qt.RightDockWidgetArea, dock3)
main.resize(400, 200)
main.show()
app.exec_()
The solution to my question was enabling the GroupedDragging with setDockOptions on the QMainWindow. I managed to get a really nice appearance & behavior exactly like I wanted with the code below.
Demo: https://www.screencast.com/t/GU5Z2ysT
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
class DockWidget(QtWidgets.QDockWidget):
def __init__(self, title: str):
super().__init__(title)
self.setTitleBarWidget(QtWidgets.QWidget())
self.dockLocationChanged.connect(self.on_dockLocationChanged)
def on_dockLocationChanged(self):
main: QtWidgets.QMainWindow = self.parent()
all_dock_widgets = main.findChildren(QtWidgets.QDockWidget)
for dock_widget in all_dock_widgets:
sibling_tabs = main.tabifiedDockWidgets(dock_widget)
# If you pull a tab out of a group the other tabs still see it as a sibling while dragging...
sibling_tabs = [s for s in sibling_tabs if not s.isFloating()]
if len(sibling_tabs) != 0:
# Hide title bar
dock_widget.setTitleBarWidget(QtWidgets.QWidget())
else:
# Re-enable title bar
dock_widget.setTitleBarWidget(None)
def minimumSizeHint(self) -> QtCore.QSize:
return QtCore.QSize(100, 100)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
main = QtWidgets.QMainWindow()
dock1 = DockWidget("Blue")
dock2 = DockWidget("Green")
dock3 = DockWidget("Red")
content1 = QtWidgets.QWidget()
content1.setStyleSheet("background-color:blue;")
content1.setMinimumSize(QtCore.QSize(50, 50))
content2 = QtWidgets.QWidget()
content2.setStyleSheet("background-color:green;")
content2.setMinimumSize(QtCore.QSize(50, 50))
content3 = QtWidgets.QWidget()
content3.setStyleSheet("background-color:red;")
content3.setMinimumSize(QtCore.QSize(50, 50))
dock1.setWidget(content1)
dock2.setWidget(content2)
dock3.setWidget(content3)
dock1.setAllowedAreas(Qt.AllDockWidgetAreas)
dock2.setAllowedAreas(Qt.AllDockWidgetAreas)
dock3.setAllowedAreas(Qt.AllDockWidgetAreas)
main.addDockWidget(Qt.LeftDockWidgetArea, dock1)
main.tabifyDockWidget(dock1, dock2)
main.addDockWidget(Qt.RightDockWidgetArea, dock3)
main.setDockOptions(main.GroupedDragging | main.AllowTabbedDocks | main.AllowNestedDocks)
main.setTabPosition(Qt.AllDockWidgetAreas, QtWidgets.QTabWidget.North)
main.resize(400, 200)
main.show()
app.exec_()
Posting this as a little extra to the accepted answer.
This version works with Qt5 and Qt6 and is able to detect corner cases like pulling out a tab and dropping it in the same group or merging a floating tab group with a docked window:
from PySide6 import QtCore, QtWidgets
from PySide6.QtCore import Qt
from typing import TypeVar, List, Optional
TDockWidget = TypeVar('TDockWidget', bound='DockWidget')
class DockWidget(QtWidgets.QDockWidget):
def __init__(self: TDockWidget, title: str, parent: Optional[QtWidgets.QWidget] = None) -> None:
super(_DockWidget, self).__init__(title, parent)
self.setTitleBarWidget(QtWidgets.QWidget())
self.visibilityChanged.connect(self.on_visibility_changed)
self.dockLocationChanged.connect(self.on_dock_location_changed)
#QtCore.Slot(bool)
def on_visibility_changed(self: TDockWidget, is_visible: bool) -> None:
# this visibility monitor is really only needed to detect merges of
# tabbed, floating windows with existing docked windows
if not is_visible and isinstance(self.parent(), QtWidgets.QMainWindow):
main_window: QtWidgets.QMainWindow = self.parent()
all_dockwidgets: List[QtWidgets.QDockWidget] = main_window.findChildren(QtWidgets.QDockWidget)
for dockwidget in all_dockwidgets:
if hasattr(dockwidget, 'on_dock_location_changed'):
dockwidget.on_dock_location_changed(main_window.dockWidgetArea(dockwidget), False)
#QtCore.Slot(Qt.DockWidgetArea)
def on_dock_location_changed(self: TDockWidget, area: Qt.DockWidgetArea, update_others: bool = True) -> None:
if not isinstance(self.parent(), QtWidgets.QMainWindow):
# mysterious parents call for a title
self.setTitleBarWidget(None)
return
main_window: QtWidgets.QMainWindow = self.parent()
if not main_window.tabifiedDockWidgets(self):
# if there's no siblings we ain't a tab!
self.setTitleBarWidget(None)
if not update_others:
# prevent infinite recursion
return
# force an update to all other docks that may now no longer be tabs
all_dockwidgets: List[QtWidgets.QDockWidget] = main_window.findChildren(QtWidgets.QDockWidget)
for dockwidget in all_dockwidgets:
if dockwidget != self and hasattr(dockwidget, 'on_dock_location_changed'):
dockwidget.on_dock_location_changed(main_window.dockWidgetArea(dockwidget), False)
return
# at this point the dockwidget is either a resting tab or a tab
# that is being dragged and hasn't been dropped yet (siblings are updated post-drop)
# collect all siblings of this dockwidget...
tab_siblings: List[QtWidgets.QDockWidget] = main_window.tabifiedDockWidgets(self)
# and filter for non-floating siblings in the same area
tab_siblings = [x for x in tab_siblings if main_window.dockWidgetArea(x) == area and not x.isFloating()]
if tab_siblings:
if self.titleBarWidget() is not None:
# no changes needed, prevent infinite recursion
return
# show a title if we're not floating (this tab is settled),
# hide it otherwise (this tab just became floating but wasn't dropped)
self.setTitleBarWidget(QtWidgets.QWidget() if not self.isFloating() else None)
# in this case it's also a good idea to tell to reconsider their situation
# since Qt won't notify them separately
for sibling in tab_siblings:
if hasattr(sibling, 'on_dock_location_changed'):
sibling.on_dock_location_changed(main_window.dockWidgetArea(sibling), True)
else:
self.setTitleBarWidget(None)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
main = QtWidgets.QMainWindow()
dock1 = DockWidget("Blue")
dock2 = DockWidget("Green")
dock3 = DockWidget("Red")
content1 = QtWidgets.QWidget()
content1.setStyleSheet("background-color:blue;")
content1.setMinimumSize(QtCore.QSize(50, 50))
content2 = QtWidgets.QWidget()
content2.setStyleSheet("background-color:green;")
content2.setMinimumSize(QtCore.QSize(50, 50))
content3 = QtWidgets.QWidget()
content3.setStyleSheet("background-color:red;")
content3.setMinimumSize(QtCore.QSize(50, 50))
dock1.setWidget(content1)
dock2.setWidget(content2)
dock3.setWidget(content3)
dock1.setAllowedAreas(Qt.AllDockWidgetAreas)
dock2.setAllowedAreas(Qt.AllDockWidgetAreas)
dock3.setAllowedAreas(Qt.AllDockWidgetAreas)
main.addDockWidget(Qt.LeftDockWidgetArea, dock1)
main.tabifyDockWidget(dock1, dock2)
main.addDockWidget(Qt.RightDockWidgetArea, dock3)
main.setDockOptions(main.GroupedDragging | main.AllowTabbedDocks | main.AllowNestedDocks)
main.setTabPosition(Qt.AllDockWidgetAreas, QtWidgets.QTabWidget.North)
main.resize(400, 200)
main.show()
app.exec_()
I got two py files. One has the main window with a QStackedWidget inside, the setCurrentWidget is set according to a condition. The other file has a widget which is dynamically added into the stacked widget and set as current widget when a button in the main window is clicked.
The widget in the second file has a dialog with a button in it. What I'm trying to do is, on clicking the button inside the dialog, the dialog should be closed and the setCurrentWidget is set according to the condition and the widget is removed from the stacked widget.
Here is what I've tried:
mainwindow.py
import sys
import os
import pathlib
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
list1 = ["item1", "item2", "item3"]
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(400, 300)
self.toolbar = QWidget()
self.toolbar.setFixedHeight(30)
self.toolbar.setStyleSheet("background: grey;")
self.button = QPushButton("Click here!")
t_layout = QHBoxLayout()
t_layout.setMargin(0)
t_layout.addWidget(self.button)
self.toolbar.setLayout(t_layout)
self.p1_label = QLabel("Such empty!")
self.p1_label.setStyleSheet("font-size: 30px;")
self.p1_label.setAlignment(Qt.AlignCenter)
self.p2_widget = QWidget()
self.p2_widget.setStyleSheet("background: orange;")
self.sw = QStackedWidget()
self.sw.addWidget(self.p1_label)
self.sw.addWidget(self.p2_widget)
if not list1:
self.sw.setCurrentWidget(self.p1_label)
else:
self.sw.setCurrentWidget(self.p2_widget)
self.mw_layout = QVBoxLayout()
self.mw_layout.addWidget(self.toolbar)
self.mw_layout.addWidget(self.sw)
self.setLayout(self.mw_layout)
def switch_widget():
import widget_test
p3 = widget_test.widget()
self.sw.addWidget(p3)
self.sw.setCurrentWidget(p3)
self.button.clicked.connect(switch_widget)
def switch_back(self):
import widget_test
p3 = widget_test.widget()
mwin = MainWindow()
sw_ = mwin.sw
sw_.removeWidget(p3)
p1 = mwin.p1_label
p2 = mwin.p2_widget
if not list1:
sw_.setCurrentWidget(p1)
else:
sw_.setCurrentWidget(p2)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
widget.py
import sys
import os
import pathlib
import datetime
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
class widget(QWidget):
def __init__(self):
super(widget, self).__init__()
self.setStyleSheet("background: teal;")
widget_label = QLabel("fluid dynamics is cool")
show_pop_up = QPushButton("show pop up")
pop_up = QDialog(self)
pop_up_label = QLabel("click below to, hopefully, get outta here")
get_outta_here = QPushButton("get outta here")
pop_up_layout = QVBoxLayout()
pop_up_layout.addWidget(pop_up_label)
pop_up_layout.addWidget(get_outta_here)
pop_up.setLayout(pop_up_layout)
def show_popup():
pop_up.show()
def get_out():
from main_test import MainWindow
MainWindow.switch_back(self)
pop_up.reject()
get_outta_here.clicked.connect(get_out)
show_pop_up.clicked.connect(show_popup)
widget_layout = QVBoxLayout()
widget_layout.addWidget(widget_label)
widget_layout.addWidget(show_pop_up)
self.setLayout(widget_layout)
I could merge the code together and make it work but I'm trying to keep the directory clean.
There is a lot going on here, but let's break it down.
The main problem seems to be juggling between modules. Eventhough it might seem appealing to import the modules back and forth, it doesn't really work. What you need to look for, is the built-in Signals module that you can utilize.
Another bigger problem is that you are re-assigning some attributes eventhough you really shouldn't. You also should revisit the condition you are using to assign the .setCurrentWidget. Currently the condition reads as if list1 doesn't exist, do this. Else, do the other. Also, switch_widget should be outside of the def __init__(self):.
I rewrote some parts of the code to make it work with signals as an example for you.
mainwindow.py
import sys
import os
import pathlib
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
from widget_test import widget
list1 = ["item1", "item2", "item3"]
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(400, 300)
self.toolbar = QWidget()
self.toolbar.setFixedHeight(30)
self.toolbar.setStyleSheet("background: grey;")
self.button = QPushButton("Click here!")
t_layout = QHBoxLayout()
t_layout.setMargin(0)
t_layout.addWidget(self.button)
self.toolbar.setLayout(t_layout)
self.p1_label = QLabel("Such empty!")
self.p1_label.setStyleSheet("font-size: 30px;")
self.p1_label.setAlignment(Qt.AlignCenter)
self.p2_widget = QWidget()
self.p2_widget.setStyleSheet("background: orange;")
self.p3 = None
self.sw = QStackedWidget()
self.sw.addWidget(self.p1_label)
self.sw.addWidget(self.p2_widget)
if not list1:
self.sw.setCurrentWidget(self.p1_label)
else:
self.sw.setCurrentWidget(self.p2_widget)
self.mw_layout = QVBoxLayout()
self.mw_layout.addWidget(self.toolbar)
self.mw_layout.addWidget(self.sw)
self.setLayout(self.mw_layout)
self.button.clicked.connect(self.switch_widget)
def switch_widget(self):
self.p3 = widget()
self.p3.update_signal.connect(self.switch_back)
self.sw.addWidget(self.p3)
self.sw.setCurrentWidget(self.p3)
def switch_back(self):
self.sw.removeWidget(self.p3)
if list1:
self.sw.setCurrentWidget(self.p1_label)
else:
self.sw.setCurrentWidget(self.p2_widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
widget.py
import sys
import os
import pathlib
import datetime
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtCore import Signal
class widget(QWidget):
update_signal = Signal()
def __init__(self):
super(widget, self).__init__()
self.setStyleSheet("background: teal;")
widget_label = QLabel("fluid dynamics is cool")
show_pop_up = QPushButton("show pop up")
pop_up = QDialog(self)
pop_up_label = QLabel("click below to, hopefully, get outta here")
get_outta_here = QPushButton("get outta here")
pop_up_layout = QVBoxLayout()
pop_up_layout.addWidget(pop_up_label)
pop_up_layout.addWidget(get_outta_here)
pop_up.setLayout(pop_up_layout)
def show_popup():
pop_up.show()
def get_out():
self.update_signal.emit()
pop_up.reject()
get_outta_here.clicked.connect(get_out)
show_pop_up.clicked.connect(show_popup)
widget_layout = QVBoxLayout()
widget_layout.addWidget(widget_label)
widget_layout.addWidget(show_pop_up)
self.setLayout(widget_layout)
Finally, check Python coding conventions for naming and other "minor" details.
Im looking to update the temp and humidity in this script.
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QWidget, QApplication, QSplitter, QLabel, QVBoxLayout, QColor
import Adafruit_DHT
import urllib2
from BeautifulSoup import BeautifulSoup
sensor_args = { '11': Adafruit_DHT.DHT11,
'22': Adafruit_DHT.DHT22,
'2302': Adafruit_DHT.AM2302 }
humidity, temperature = Adafruit_DHT.read_retry(11, 4)
temp = 'Temp={0:0.1f}* Humidity={1:0.1f}%'.format(temperature, humidity)
soup = BeautifulSoup(urllib2.urlopen('http://partner.mlb.com/partnerxml/gen/news/rss/bos.xml').read())
title = soup.find('item').title
desc = soup.find('item').description
url = soup.find('item').guid
temperature = temperature * 9/5.0 + 32
class MyWidget(QWidget):
def __init__( self, parent = None ):
super(MyWidget, self).__init__(parent)
# create widgets
a = QLabel('Humidity:{:0.1f}%'.format(humidity),self )
a.setMinimumSize(100, 100)
b = QLabel('Temperature:{:0.1f}F'.format(temperature),self )
b.setMinimumSize(100, 100)
c = QLabel("Redsox News \nTitle: %s\nSummary: %s " % (title.text, desc.text), self)
c.setWordWrap(True)
c.setMinimumSize(280, 200)
d = QLabel("This is some bullshit wordwrap and i cant get it tow work", self)
d.setWordWrap(True)
d.setMinimumSize(180, 300)
for lbl in (a, b, c, d):
lbl.setAlignment(Qt.AlignLeft)
# create 2 horizontal splitters
h_splitter1 = QSplitter(Qt.Horizontal, self)
h_splitter1.addWidget(a)
h_splitter1.addWidget(b)
h_splitter2 = QSplitter(Qt.Horizontal, self)
h_splitter2.addWidget(c)
h_splitter2.addWidget(d)
h_splitter1.splitterMoved.connect(self.moveSplitter)
h_splitter2.splitterMoved.connect(self.moveSplitter)
self._spltA = h_splitter1
self._spltB = h_splitter2
# create a vertical splitter
v_splitter = QSplitter(Qt.Vertical, self)
v_splitter.addWidget(h_splitter1)
v_splitter.addWidget(h_splitter2)
layout = QVBoxLayout()
layout.addWidget(v_splitter)
self.setLayout(layout)
#color widget code
palette = self.palette()
role = self.backgroundRole()
palette.setColor(role, QColor('black'))
self.setPalette(palette)
a.setStyleSheet("QLabel {color:yellow}")
b.setStyleSheet("QLabel {color:yellow}")
c.setStyleSheet("QLabel {background-color: black; color:white}")
d.setStyleSheet("QLabel {background-color: black; color:white}")
#self.setWindowFlags(Qt.CustomizeWindowHint)
timer=self.QTimer()
timer.start(5000)
timer.timeout.connect(self.temp.update)
def moveSplitter( self, index, pos ):
splt = self._spltA if self.sender() == self._spltB else self._spltB
splt.blockSignals(True)
#splt.moveSplitter(index, pos)
splt.blockSignals(False)
if ( __name__ == '__main__' ):
app = QApplication([])
widget = MyWidget()
widget.show()
app.exec_()
Ive been learning a lot about pyQt and all the ins and outs of it. Slow going i might add as i am very new to python.
What I would like is to have it so that this updates the temp and humidity every 5 minutes. I have tried this..
timer=self.QTimer()
timer.start(300)
timer.timeout.connect(self.temp.update)
This does not seem to work for me. I get the error no attribute QTimer.
(Note, I'm not really familiar with pyqt, so if this is wrong, please let me know and I'll delete the answer...)
The line
timer=self.QTimer()
is wrong. this is a QWidget subclass, which does not have QTimer attribute. In fact, QTimer is a regular Qt class, so that line should simply be:
timer = QTimer()
You also need the right import, of course, which I think is:
from PyQt4.QtCore import QTimer