I am trying to build a GUI for my Twitter application that automatically follows people. I have it mostly working in the console, however I am trying to convert it into a GUI, and am running into a few issues. The main problem is that whenever I assign the script I want to run when a button is pushed, it either runs immediately when I run the app, which wont display the GUI; or the GUI displays, but the function on the button does nothing. I have been looking for days, but I do not know what the problem is.
#! /usr/bin/python
import time
import tweepy
from keys import keys
import requests_cache
from random import randint
from PyQt4 import QtGui
from PyQt4 import QtCore
from subprocess import call
import sys
from AddToDB import *
SCREEN_NAME = 'JonahHensley'
CONSUMER_KEY = keys['consumer_key']
CONSUMER_SECRET = keys['consumer_secret']
ACCESS_TOKEN = keys['access_token']
ACCESS_TOKEN_SECRET = keys['access_token_secret']
auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
api = tweepy.API(auth)
followers = api.followers_ids(SCREEN_NAME)
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
btn = QtGui.QPushButton('Yes', self)
btn.clicked.connect(follower.follow(self))
btn.resize(180, 40)
btn.move(20, 35)
qbtn = QtGui.QPushButton('No', self)
qbtn.clicked.connect(QtCore.QCoreApplication.instance().quit)
qbtn.resize(180, 40)
qbtn.move(20, 80)
self.setWindowTitle('Test')
self.show()
class follower(QtGui.QWidget):
def follow(self):
while True:
try:
for f in followers:
UserFollow = input("Follow users from: ")
print('Getting followers from ' + UserFollow)
api.wait_on_rate_limit = True
api.wait_on_rate_limit_notify = True
requests_cache.install_cache(cache_name='twitter_cache', backend='sqlite', expire_after=180)
print("followed {0}".format(api.get_user(f).screen_name))
api.create_friendship(f)
randnum = randint(10, 25)
randnumdisplay = print("Delaying next follow for " + str(randnum) + " seconds.")
print(str(randnumdisplay))
screen_names = [api.get_user(f).screen_name]
time.sleep(randnum)
except tweepy.TweepError:
print("Waiting till next interval...")
time.sleep(60 * 15)
continue
except StopIteration:
def main():
app = QtGui.QApplication(sys.argv)
gui = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main() break
def main():
app = QtGui.QApplication(sys.argv)
gui = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Related
this code opens web site with Qt browser. If internet connection is lost I want to give Information message with QMessageBox:
import sys
from PyQt5.QtCore import *
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QLabel
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtGui import QGuiApplication as App
from PyQt5.QtGui import QPixmap, QWindow
from PyQt5 import QtNetwork, QtCore, QtWidgets
import urllib
from urllib.request import urlopen
import threading
import time
class WebApp(QMainWindow):
def __init__(self):
self.is_connected = None
self.is_msgshow = True
self.msg = QtWidgets.QMessageBox()
super().__init__()
self.title = "OZI"
self.t_internet = threading.Thread(target=self.is_internet)
self.t_internet.start()
self.t_refreshpage = threading.Thread(target=self.refresh_page)
self.t_refreshpage.start()
self.web = QWebEngineView()
self.web.window().setWindowTitle(self.title)
self.web.load(QUrl("http://www.google.com"))
self.web.showFullScreen()
def is_internet(self):
"""
Query internet using python
:return:
"""
while True:
time.sleep(5)
try:
urlopen("http://www.google.com", timeout=1)
self.is_connected = True
except urllib.error.URLError as Error:
print(Error)
self.is_connected = False
print(self.is_connected)
def refresh_page(self):
while True:
time.sleep(.1)
if self.is_connected == False:
time.sleep(5)
if self.is_connected == True:
self.web.page().action(QWebEnginePage.Reload).trigger()
else:
if self.is_msgshow == True:
print('testtt')
self.msg.information(None, 'INFO', 'PLEASE CHECK YOUR INTERNET CONNECTION!!!')
self.is_msgshow = False
self.msg.close()
else:
pass
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = WebApp()
sys.exit(app.exec_())
However, I couldn't succeed at
if self.is_msgshow == True:
print('testtt')
this part while internet connection is lost my code opens many MessageBox. I guess my fault is controlling self.is_msgshow flag.
Far beyond the problem you are pointing out, you have other errors and it is more dangerous than the one indicated: You should not access the GUI from another thread, and you should also not access the same variable from 2 threads without protecting it through a mutex, semaphore or Similary. For example, you are calling self.web.page().action(QWebEnginePage.Reload).trigger() and self.msg.information(None, 'INFO', 'PLEASE CHECK YOUR INTERNET CONNECTION!!!') from the secondary thread, and the variable "is_connected" is accessed by several threads.
Another error is that method QMessage::information() is static and generates a new object that is not directly accessible, instead you must use the object "self.msg" through its own methods to display the necessary information.
Considering the above I have created a class that is only responsible for analyzing the status of the connection and if it changes to emit a signal. To send information between threads in Qt you can use signals or QMetaObject::invokedMethod() in addition to the classic mutex and semaphores.
Then it is only necessary to analyze the value of the status sent to the GUI to implement the logic:
import sys
import threading
import time
import urllib
from urllib.request import urlopen
from PyQt5 import QtCore, QtWidgets, QtNetwork, QtWebEngineWidgets
class ConnectivityManager(QtCore.QObject):
statusChanged = QtCore.pyqtSignal(bool)
def __init__(self, *, timeout=4000, parent=None):
super().__init__(parent)
self._status = False
self._timeout = timeout
def start(self):
threading.Thread(target=self._check, daemon=True).start()
#QtCore.pyqtProperty(bool, notify=statusChanged)
def status(self):
return self._status
#QtCore.pyqtSlot(bool)
def _update_status(self, status):
if self._status != status:
self._status = status
self.statusChanged.emit(self.status)
def _check(self):
while True:
try:
urlopen("http://www.google.com", timeout=1)
status = True
except urllib.error.URLError as Error:
status = False
QtCore.QMetaObject.invokeMethod(
self,
"_update_status",
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(bool, status),
)
time.sleep(5)
class WebApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("OZI")
self.web = QtWebEngineWidgets.QWebEngineView()
self.setCentralWidget(self.web)
self.web.load(QtCore.QUrl("http://www.google.com"))
self.connectivity_manager = ConnectivityManager()
self.connectivity_manager.statusChanged.connect(self.on_status_changed)
self.connectivity_manager.start()
self.msg = QtWidgets.QMessageBox()
self.msg.setWindowTitle("INFO")
self.msg.setText("PLEASE CHECK YOUR INTERNET CONNECTION!!!")
#QtCore.pyqtSlot(bool)
def on_status_changed(self, status):
if status:
self.msg.hide()
self.statusBar().showMessage("Connected")
self.web.page().action(QtWebEngineWidgets.QWebEnginePage.Reload).trigger()
else:
self.statusBar().showMessage("Disconnected")
self.msg.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = WebApp()
ex.showFullScreen()
sys.exit(app.exec_())
On the other hand, the same logic can be implemented using QtNetwork without the need for threads:
import sys
from PyQt5 import QtCore, QtWidgets, QtNetwork, QtWebEngineWidgets
class ConnectivityManager(QtCore.QObject):
statusChanged = QtCore.pyqtSignal(bool)
def __init__(self, *, timeout=4000, parent=None):
super().__init__(parent)
self._status = False
self._timeout = timeout
self.manager = QtNetwork.QNetworkAccessManager()
self._timer = QtCore.QTimer(
singleShot=True, interval=self._timeout, timeout=self.verify_status
)
def start(self):
QtCore.QTimer.singleShot(0, self._check)
#QtCore.pyqtProperty(bool, notify=statusChanged)
def status(self):
return self._status
#QtCore.pyqtSlot(bool)
def _update_status(self, status):
if self._status != status:
self._status = status
self.statusChanged.emit(self.status)
def _check(self):
url = QtCore.QUrl("https://www.google.com/")
req = QtNetwork.QNetworkRequest(url)
self._reply = self.manager.get(req)
self._reply.finished.connect(self.verify_status)
self._timer.start()
#QtCore.pyqtSlot()
def verify_status(self):
if self._timer.isActive():
self._timer.stop()
if self._reply.error() == QtNetwork.QNetworkReply.NoError:
v = self._reply.attribute(
QtNetwork.QNetworkRequest.HttpStatusCodeAttribute
)
if 200 <= v < 300:
self._update_status(True)
else:
print("error", "code error: {}".format(v))
self._update_status(False)
else:
print("error", self._reply.errorString())
self._update_status(False)
else:
self._reply.finished.disconnect(self.verify_status)
self._reply.abort()
print("Timeout")
self._update_status(False)
QtCore.QTimer.singleShot(5000, self._check)
self._reply.deleteLater()
class WebApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("OZI")
self.web = QtWebEngineWidgets.QWebEngineView()
self.setCentralWidget(self.web)
self.web.load(QtCore.QUrl("http://www.google.com"))
self.connectivity_manager = ConnectivityManager()
self.connectivity_manager.statusChanged.connect(self.on_status_changed)
self.connectivity_manager.start()
self.msg = QtWidgets.QMessageBox()
self.msg.setWindowTitle("INFO")
self.msg.setText("PLEASE CHECK YOUR INTERNET CONNECTION!!!")
#QtCore.pyqtSlot(bool)
def on_status_changed(self, status):
if status:
self.msg.hide()
self.statusBar().showMessage("Connected")
self.web.page().action(QtWebEngineWidgets.QWebEnginePage.Reload).trigger()
else:
self.statusBar().showMessage("Disconnected")
self.msg.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = WebApp()
ex.showFullScreen()
sys.exit(app.exec_())
I do not know the pyqt5 at all but guessing by flow of your code, here:
if self.is_msgshow == True:
print('testtt')
self.msg.information(None, 'INFO', 'PLEASE CHECK YOUR INTERNET CONNECTION!!!')
self.is_msgshow = False
self.msg.close()
It seems the self.msg.information() call is expected to be synchronous. If that is so, then as long as it remains open, the is_msgshow is still True because you changing it once you got dialog closed. And this is your bug as if new even occurs then nothing blocks new dialog from being shown. The fix is pretty simple - just move self.is_msgshow = False to be very first thing done in that code block, you should be good:
if self.is_msgshow:
self.is_msgshow = False
print('testtt')
self.msg.information(None, 'INFO', 'PLEASE CHECK YOUR INTERNET CONNECTION!!!')
self.msg.close()
Additional note, you may want to reset it back to True once connectivity is restored otherwise you won't show a thing next time network is down.
The QMessageBox class provides a modal dialog for informing the user or for asking the user a question and receiving an answer.
https://doc.qt.io/qtforpython/PySide2/QtWidgets/QMessageBox.html
I made this code .. A new window should open when i fill the requirements and press login but when i do that the window open then it disappears .. i saw a lot of codes using OOP but i don't understand them so i need any one to give me a simple solution
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
import os
import shutil
app = QApplication(sys.argv)
main_window = QWidget()
main_window.setWindowTitle("Keep It Safe V1.5")
main_window.setWindowIcon(QIcon('lock.png'))
main_window.resize(350, 180)
main_window.move(500, 200)
login_btn = QPushButton('Login', main_window)
login_btn.resize(150, 30)
login_btn.move(100, 120)
User = QLineEdit(main_window)
User.resize(250, 30)
User.move(50, 10)
User.setPlaceholderText('Enter your user name')
password = QLineEdit(main_window)
password.resize(250, 30)
password.move(50, 60)
password.setPlaceholderText('Enter your passsword')
password.setEchoMode(QLineEdit.Password)
check = QCheckBox(main_window, text="I accept the terms and policies")
check.move(50, 95)
def login_check():
user = User.text()
Pass = password.text()
if user == "Admin" and Pass == "admin" and check.isChecked():
print("Clicked")
sec_win =QWidget()
l = QLabel(sec_win , text = "second window opened")
sec_win.show()
else:
fai = QMessageBox.warning(main_window, "Error", "Incorrect user name or passwprd")
login_btn.clicked.connect(login_check)
main_window.show()
app.exec_()
A variable that is created within a function is local, so it will be deleted when it is finished executing, and sec_win is so it will be displayed but an instant later it will be removed, the solution is to create it before and only show it when necessary.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
app = QApplication(sys.argv)
main_window = QWidget()
main_window.setWindowTitle("Keep It Safe V1.5")
main_window.setWindowIcon(QIcon('lock.png'))
main_window.resize(350, 180)
main_window.move(500, 200)
login_btn = QPushButton('Login', main_window)
login_btn.resize(150, 30)
login_btn.move(100, 120)
User = QLineEdit(main_window)
User.resize(250, 30)
User.move(50, 10)
User.setPlaceholderText('Enter your user name')
password = QLineEdit(main_window)
password.resize(250, 30)
password.move(50, 60)
password.setPlaceholderText('Enter your passsword')
password.setEchoMode(QLineEdit.Password)
check = QCheckBox(main_window, text="I accept the terms and policies")
check.move(50, 95)
sec_win =QWidget()
def login_check():
user = User.text()
Pass = password.text()
if user == "Admin" and Pass == "admin" and check.isChecked():
print("Clicked")
l = QLabel(sec_win , text = "second window opened")
sec_win.show()
else:
fai = QMessageBox.warning(main_window, "Error", "Incorrect user name or passwprd")
login_btn.clicked.connect(login_check)
main_window.show()
sys.exit(app.exec_())
Just a simple problem (not for me): when I close the window, the program is still running. Here is the code:
from PyQt4 import QtCore, QtGui
from PyQt4.Qt import QString
import sys
import sensors
from sensors import *
import threading
class MainWindow(QtGui.QWidget):
signalUpdate = QtCore.pyqtSignal() # 1 - define a new signal in mainwindow class
# 2 -connect this signal to the update() function
#emit signal
#main window
def __init__(self):
#vars for core temp and name
self.tempValue = 0
self.name = '0'
super(MainWindow, self).__init__()
self.setGeometry(50, 50, 250, 150)
self.setWindowTitle("Title here")
self.setFixedSize(250, 150)
self.home()
#make widgets (progressBar and labe)
def home(self):
self.prgB = QtGui.QProgressBar(self)
self.prgB.setGeometry(20, 20, 210, 20)
#self.prgB.setOrientation(QtCore.Qt.Vertical)
QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("motif"))#stles -> motif, Plastique, Windows
self.lbl = QtGui.QLabel(self)
self.lbl.setGeometry(60, 40, 210, 20)
self.signalUpdate.connect(self.update) #connect this signal to the update() function
lay = QtGui.QVBoxLayout()
lay.addWidget(self.prgB)
lay.addWidget(self.lbl)
self.setLayout(lay)
self.tmp()
self.show()
#update() to update label and progressbar values
def update(self):
textas = ('%s : %.1f' % (self.name, self.tempValue))
self.lbl.setText(str(textas + ' C'))
self.prgB.setFormat(QString.number(self.tempValue)+ ' C')
self.prgB.setValue(self.tempValue)
#temp() to get chip data from sensors (temp, name etc)
def tmp(self):
sensors.init()
try:
for chip in sensors.iter_detected_chips():
#print (chip)
#print('Adapter:', chip.adapter_name)
for feature in chip:
if feature.label == 'Physical id 0':
self.tempValue = feature.get_value()
self.name = feature.label
#print ('%s (%r): %.1f' % (feature.name, feature.label, feature.get_value()))
threading.Timer(2.0, self.tmp).start()
self.signalUpdate.emit() #emit signal
#print
finally:
sensors.cleanup()
def run():
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads)
app = QtGui.QApplication(sys.argv)
GUI = MainWindow()
sys.exit(app.exec_())
run()
Why is that happening, and how to fix it? (I was trying to research on google and yes there are many forums with same question but I get no luck so far to fix it).
EDIT: problem is still not fixed, can someone show/tell how to stop threading.Time on program exit? Please :)
Call the timer's cancel() method in your widget's (overridden) closeEvent() method:
def tmp(self):
...
self.timer = threading.Timer(2.0, self.tmp)
self.timer.start()
self.signalUpdate.emit() #emit signal
def closeEvent(self):
self.timer.cancel()
I've tested that this works:
without the threading, app exits;
with the threading.Timer, but without the timer cancel, app never exits;
with the timer cancel, app exits
This is a pyside GUI, I have created 2 panel in 2 different .py files, main.py and sub.py each panel will display a we browser 'QWebView'. Currently when user press the button on main.py it will redirect the user to a page e.g "www.google" and user will have to click the button on sub.py to be redirected to e.g"www.facebook.com" they work as a indipendent function.
I would like to ask is there a way to link both together where user press the button on main.py and both webbrower will change together?
Yes, you can have multiple items triggered by the same connection.
QObject::connect(myButton, SIGNAL(clicked()),
this, SLOT(launchGoogleSiteOnBrowserA());
QObject::connect(myButton, SIGNAL(clicked()),
pointerToOtherClass, SLOT(launchFacebookSiteOnBrowserB());
http://qt-project.org/doc/qt-4.8/signalsandslots.html
EDIT: Following some another answer about using signals and slots in PyQt...
https://stackoverflow.com/a/7618282/999943
Here is a way to do it in PyQt:
widget.pyw
from PyQt4 import QtCore, QtGui
from mybrowser import Browser
class Widget(QtGui.QWidget):
def __init__(self):
super(Widget, self).__init__()
self.myButton = QtGui.QPushButton('Open Facebook and Google')
self.myHLayout = QtGui.QHBoxLayout()
self.myVLayout = QtGui.QVBoxLayout()
self.myVLayout.addWidget(self.myButton)
url = QtCore.QUrl('http://www.yahoo.com')
self.browserLHS = Browser(url)
self.browserRHS = Browser(url)
self.myHLayout.addWidget(self.browserLHS)
self.myHLayout.addWidget(self.browserRHS)
QtCore.QObject.connect(self.myButton, QtCore.SIGNAL("clicked()"), self.changePageOnBothBrowsers )
self.myVLayout.addLayout(self.myHLayout)
self.setLayout(self.myVLayout)
def changePageOnBothBrowsers(self):
self.browserLHS.load(QtCore.QUrl.fromUserInput('google.com'))
self.browserRHS.load(QtCore.QUrl.fromUserInput('facebook.com'))
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
widget = Widget()
widget.show()
sys.exit(app.exec_())
mybrowser.pyw
from PyQt4 import QtCore, QtGui, QtNetwork, QtWebKit
import jquery_rc
class Browser(QtWebKit.QWebView):
def __init__(self, url):
super(Browser, self).__init__()
self.progress = 0
fd = QtCore.QFile(":/jquery.min.js")
if fd.open(QtCore.QIODevice.ReadOnly | QtCore.QFile.Text):
self.jQuery = QtCore.QTextStream(fd).readAll()
fd.close()
else:
self.jQuery = ''
QtNetwork.QNetworkProxyFactory.setUseSystemConfiguration(True)
self.load(url)
self.loadFinished.connect(self.adjustLocation)
self.titleChanged.connect(self.adjustTitle)
self.loadProgress.connect(self.setProgress)
self.loadFinished.connect(self.finishLoading)
self.locationEdit = QtGui.QLineEdit(self)
self.locationEdit.setSizePolicy(QtGui.QSizePolicy.Expanding,
self.locationEdit.sizePolicy().verticalPolicy())
self.locationEdit.returnPressed.connect(self.changeLocation)
def adjustLocation(self):
self.locationEdit.setText(self.url().toString())
def changeLocation(self):
url = QtCore.QUrl.fromUserInput(self.locationEdit.text())
self.load(url)
self.setFocus()
def adjustTitle(self):
if 0 < self.progress < 100:
self.setWindowTitle("%s (%s%%)" % (self.title(), self.progress))
else:
self.setWindowTitle(self.title())
def setProgress(self, p):
self.progress = p
self.adjustTitle()
def finishLoading(self):
self.progress = 100
self.adjustTitle()
self.page().mainFrame().evaluateJavaScript(self.jQuery)
#if __name__ == '__main__':
#
# import sys
#
# app = QtGui.QApplication(sys.argv)
#
# if len(sys.argv) > 1:
# url = QtCore.QUrl(sys.argv[1])
# else:
# url = QtCore.QUrl('http://www.google.com/ncr')
#
# browser = Browser(url)
# browser.show()
#
# sys.exit(app.exec_())
Hope that helps.
I'm trying to parse webpages generated by js with qtwebkit, I found an example of how to get page source:
import sys
from PySide.QtGui import *
from PySide.QtCore import *
from PySide.QtWebKit import *
class Render(QWebPage):
def __init__(self, url):
self.app = QApplication(sys.argv)
QWebPage.__init__(self)
self.loadFinished.connect(self._loadFinished)
self.mainFrame().load(QUrl(url))
self.app.exec_()
def _loadFinished(self, result):
self.frame = self.mainFrame()
self.app.quit()
url = 'http://www.thesite.gov/search'
r = Render(url)
html = r.frame.toHtml()
But i don't know how to make it work in threads.
So, how to do this and if it's not possible - is there another fast way to get wepages generated by js?
Given QT's async nature, the QtWebkit methods are non-blocking as well, so there is no point running them in threads. You can start them parallelly like this:
from functools import partial
from PySide.QtCore import QUrl
from PySide.QtGui import QApplication
from PySide.QtWebKit import QWebView, QWebSettings
TARGET_URLS = (
'http://stackoverflow.com',
'http://github.com',
'http://bitbucket.org',
'http://news.ycombinator.com',
'http://slashdot.org',
'http://www.reddit.com',
'http://www.dzone.com',
'http://www.ideone.com',
'http://jsfiddle.net',
)
class Crawler(object):
def __init__(self, app):
self.app = app
self.results = dict()
self.browsers = dict()
def _load_finished(self, browser_id, ok):
print ok, browser_id
web_view, _flag = self.browsers[browser_id]
self.browsers[browser_id] = (web_view, True)
frame = web_view.page().mainFrame()
self.results[frame.url()] = frame.toHtml()
web_view.loadFinished.disconnect()
web_view.stop()
if all([closed for bid, closed in self.browsers.values()]):
print 'all finished'
self.app.quit()
def start(self, urls):
for browser_id, url in enumerate(urls):
web_view = QWebView()
web_view.settings().setAttribute(QWebSettings.AutoLoadImages,
False)
loaded = partial(self._load_finished, browser_id)
web_view.loadFinished.connect(loaded)
web_view.load(QUrl(url))
self.browsers[browser_id] = (web_view, False)
if __name__ == '__main__':
app = QApplication([])
crawler = Crawler(app)
crawler.start(TARGET_URLS)
app.exec_()
print 'got:', crawler.results.keys()