from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QPlainTextEdit, QVBoxLayout, QWidget
from PyQt5.QtCore import QProcess
import subprocess
import sys
import time
import datetime
current_time = datetime.datetime.now()
current_time = current_time.strftime('%Y-%m-%d %H:%M')
class TextUpdate():
def watch_list(self):
self = open(r"C:\Users\Administrator\Desktop\stat_arb\gui\watchlist.txt", 'r').read()
return self
def order_history(self):
self = open(r"C:\Users\Administrator\Desktop\stat_arb\gui\orderhistory.txt", 'r').read()
return self
def re_turn(self):
self = open(r"C:\Users\Administrator\Desktop\stat_arb\gui\return.txt", 'r').read()
return self
def net_value(self):
self = open(r"C:\Users\Administrator\Desktop\stat_arb\gui\netvalue.txt", 'r').read()
return self
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(915, 413)
MainWindow.setStyleSheet(
"background-color: rgb(42, 42 , 42)")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.p = None
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.frame = QtWidgets.QFrame(self.centralwidget)
self.frame.setStyleSheet(
"background-color: rgb(42, 42 , 42)")
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.frame_2 = QtWidgets.QFrame(self.frame)
self.frame_2.setGeometry(QtCore.QRect(20, 30, 411, 221))
self.frame_2.setStyleSheet(
"background-color: #202020;\n"
"border-radius: 12px")
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_2.setObjectName("frame_2")
self.watch_text = QtWidgets.QPlainTextEdit(self.frame_2)
self.watch_text.setGeometry(QtCore.QRect(10, 40, 391, 121))
self.watch_text.setMouseTracking(False)
self.watch_text.setStyleSheet(
"border:0;\n"
"font-size: 11px;\n"
"color: #9e9e9e")
self.watch_text.setBackgroundVisible(False)
self.watch_text.setObjectName("watch_text")
self.watch_label = QtWidgets.QPlainTextEdit(self.frame_2)
self.watch_label.setGeometry(QtCore.QRect(10, 10, 391, 31))
self.watch_label.setStyleSheet(
"border:0;\n"
"font-size: 10px;\n"
"font-weight: bold;\n"
"color: #ffffff")
self.watch_label.setObjectName("watch_label")
self.start_button = QtWidgets.QPushButton(self.frame_2)
self.start_button.setGeometry(QtCore.QRect(100, 180, 221, 28))
self.start_button.setStyleSheet(
"background-color: #61ac3e;\n"
"border-radius: 8px;\n"
"font-size: 10px;\n"
"font-weight: bold;\n"
"color: #ffffff")
self.start_button.setObjectName("start_button")
self.frame_3 = QtWidgets.QFrame(self.frame)
self.frame_3.setGeometry(QtCore.QRect(20, 260, 411, 101))
self.frame_3.setStyleSheet(
"background-color: #202020;\n"
"border-radius: 12px")
self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_3.setObjectName("frame_3")
self.output_text = QtWidgets.QPlainTextEdit(self.frame_3)
self.output_text.setGeometry(QtCore.QRect(10, 40, 391, 51))
self.output_text.setMouseTracking(False)
self.output_text.setStyleSheet(
"border:0;\n"
"font-size: 11px;\n"
"color: #9e9e9e;")
self.output_text.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.output_text.setBackgroundVisible(False)
self.output_text.setObjectName("output_text")
self.output_label = QtWidgets.QPlainTextEdit(self.frame_3)
self.output_label.setGeometry(QtCore.QRect(10, 10, 391, 31))
self.output_label.setStyleSheet("border:0;\n"
"font-size: 10px;\n"
"font-weight: bold;\n"
"color: #ffffff")
self.output_label.setObjectName("output_label")
self.frame_4 = QtWidgets.QFrame(self.frame)
self.frame_4.setGeometry(QtCore.QRect(450, 140, 411, 221))
self.frame_4.setStyleSheet(
"background-color: #202020;\n"
"border-radius: 12px")
self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_4.setObjectName("frame_4")
self.order_text = QtWidgets.QPlainTextEdit(self.frame_4)
self.order_text.setGeometry(QtCore.QRect(10, 40, 391, 161))
self.order_text.setMouseTracking(False)
self.order_text.setStyleSheet(
"border:0;\n"
"font-size: 11px;\n"
"color: #9e9e9e")
self.order_text.setBackgroundVisible(False)
self.order_text.setObjectName("order_text")
self.order_label = QtWidgets.QPlainTextEdit(self.frame_4)
self.order_label.setGeometry(QtCore.QRect(10, 10, 391, 31))
self.order_label.setStyleSheet(
"border:0;\n"
"font-size: 10px;\n"
"font-weight: bold;\n"
"color: #ffffff")
self.order_label.setObjectName("order_label")
self.frame_5 = QtWidgets.QFrame(self.frame)
self.frame_5.setGeometry(QtCore.QRect(450, 30, 411, 101))
self.frame_5.setStyleSheet(
"background-color: #202020;\n"
"border-radius: 12px")
self.frame_5.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_5.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_5.setObjectName("frame_5")
self.nav_text = QtWidgets.QPlainTextEdit(self.frame_5)
self.nav_text.setGeometry(QtCore.QRect(10, 40, 181, 41))
self.nav_text.setMouseTracking(False)
self.nav_text.setBackgroundVisible(False)
self.nav_text.setObjectName("nav_text")
self.nav_text.setStyleSheet(
"border:0;\n"
"font-size: 24px;\n"
"color: #1a62dd")
self.nav_label = QtWidgets.QPlainTextEdit(self.frame_5)
self.nav_label.setGeometry(QtCore.QRect(10, 10, 181, 31))
self.nav_label.setStyleSheet(
"border:0;\n"
"font-size: 10px;\n"
"font-weight: bold;\n"
"color: #ffffff")
self.nav_label.setObjectName("nav_label")
self.return_text = QtWidgets.QPlainTextEdit(self.frame_5)
self.return_text.setGeometry(QtCore.QRect(210, 40, 181, 41))
self.return_text.setMouseTracking(False)
self.return_text.setBackgroundVisible(False)
self.return_text.setObjectName("return_text")
self.return_text.setStyleSheet(
"border:0;\n"
"font-size: 24px;\n"
"color: #9e9e9e")
self.return_label = QtWidgets.QPlainTextEdit(self.frame_5)
self.return_label.setGeometry(QtCore.QRect(210, 10, 181, 31))
self.return_label.setStyleSheet(
"border:0;\n"
"font-size: 10px;\n"
"font-weight: bold;\n"
"color: #ffffff")
self.return_label.setObjectName("return_label")
self.gridLayout.addWidget(self.frame, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
self.timer = QtCore.QTimer()
self.timer.start(5)
self.timer.timeout.connect(lambda:self.watch_text.setPlainText(TextUpdate().watch_list()))
self.timer.timeout.connect(lambda:self.order_text.setPlainText(TextUpdate().order_history()))
self.timer.timeout.connect(lambda:self.return_text.setPlainText(TextUpdate().re_turn()))
self.timer.timeout.connect(lambda:self.nav_text.setPlainText(TextUpdate().net_value()))
self.start_button.pressed.connect(self.start_process)
self.output_text.setReadOnly(True)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.watch_label.setPlainText(_translate("MainWindow", " WATCHLIST"))
self.start_button.setText(_translate("MainWindow", "START"))
self.output_label.setPlainText(_translate("MainWindow", " OUTPUT"))
self.order_label.setPlainText(_translate("MainWindow", " ORDER HISTORY"))
self.nav_label.setPlainText(_translate("MainWindow", " NET VALUE"))
self.return_label.setPlainText(_translate("MainWindow", " %RETURN"))
def message(self, s):
self.output_text.appendPlainText(s)
def start_process(self):
if self.p is None: # No process running.
self.message(f'[STATUS] {current_time} Initializing process...')
self.p = QProcess() # Keep a reference to the QProcess (e.g. on self) while it's running.
self.p.readyReadStandardOutput.connect(self.handle_stdout)
self.p.readyReadStandardError.connect(self.handle_stderr)
self.p.stateChanged.connect(self.handle_state)
self.p.finished.connect(self.process_finished) # Clean up once complete.
# environment path,script.py path
self.p.start(r'C:\Users\Administrator\PycharmProjects\pythonProject\venv\Scripts\python.exe',
[r"C:\Users\Administrator\Desktop\stat_arb\31b_aug.py"])
def handle_stderr(self):
data = self.p.readAllStandardError()
stderr = bytes(data).decode("utf8")
self.message(stderr)
def handle_stdout(self):
data = self.p.readAllStandardOutput()
stdout = bytes(data).decode("utf8")
self.message(stdout)
def handle_state(self, state):
states = {
QProcess.NotRunning: 'Not running...',
QProcess.Starting: 'Starting...',
QProcess.Running: 'Running...',
}
state_name = states[state]
self.message(f'[STATUS] {current_time} {state_name}')
def process_finished(self):
self.message("Process finished.")
self.p = None
def get_termi_futu():
subprocess.call("taskkill /F /IM FutuOpenD.exe")
print('[DISCONNECTED]', current_time, ' Connection status. Trading account is disconnected.')
if name == "main":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
app.exec_()
get_termi_futu()
the %return is updating font color only if the GUI is restarted.
figure it out and added this:
def font_color():
if float(TextUpdate().re_turn()) > 0:
self = ("border:0;\n"
"font-size: 24px;\n"
"color: #23df0a")
return self
else:
self = (
"border:0;\n"
"font-size: 24px;\n"
"color: #e41a13")
return self
self.timer = QtCore.QTimer()
self.timer.start(5)
self.timer.timeout.connect(lambda:self.return_text.setStyleSheet(font_color()))
Related
Problem
I want to Remove the Focus from QLineEdit when I click somewhere else on the window.
I'm using PyQt5 in Python 3.9.7 on Windows 10
I've also searched about this on google, youtube and stackoverflow. But Seems the api was outdated/Not for PyQt5.
Code
I was Making a URL Shortener for Educational Purpose Only (Cz I'm Beginner:)
and I'm using My own class Entrybox which is parent to QLineEdit
Here is the code:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMessageBox
from requests import get
from pyperclip import copy
from keyboard import add_hotkey
class Entrybox(QtWidgets.QLineEdit):
pass
class Ui_window(object):
def setupUi(self, window):
self.win=window
self.win.setFixedSize(400, 247)
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(10)
window.setFont(font)
window.setAutoFillBackground(False)
window.setStyleSheet("background-color: #484848;")
window.setUnifiedTitleAndToolBarOnMac(False)
self.centralwidget = QtWidgets.QWidget(window)
self.centralwidget.setObjectName("centralwidget")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(0, 10, 400, 31))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(20)
self.label.setFont(font)
self.label.setStyleSheet("color:#fff;")
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.boxurl = Entrybox(self.centralwidget)
self.boxurl.setGeometry(QtCore.QRect(10, 60, 380, 31))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(12)
self.boxurl.setFont(font)
self.boxurl.setStyleSheet("Entrybox {\n"
"background-color: #595959;\n"
"border:0px;\n"
"color:#ffffff;\n"
"selection-color: #ffffff;\n"
"selection-background-color: #484848;\n"
"border-radius: 15px;\n"
"}\n"
"Entrybox:hover {\n"
"background-color: #636363;\n"
"}\n"
"Entrybox:focus {\n"
"background-color: #636363;\n"
"}")
self.boxurl.setAlignment(QtCore.Qt.AlignCenter)
self.boxurl.setObjectName("boxurl")
self.gobtn = QtWidgets.QPushButton(self.centralwidget)
self.gobtn.setGeometry(QtCore.QRect(160, 160, 81, 41))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(15)
font.setBold(True)
font.setWeight(75)
self.gobtn.setFont(font)
self.gobtn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
self.gobtn.setStyleSheet("QPushButton {\n"
"background-color: #505050;\n"
"border:0px;\n"
"color:#ffffff;\n"
"border-radius:15px;\n"
"}\n"
"QPushButton:hover {\n"
"background-color: #595959;\n"
"}\n"
"QPushButton:pressed {\n"
"background-color: #636363;\n"
"}")
self.gobtn.setObjectName("gobtn")
self.boxname = Entrybox(self.centralwidget)
self.boxname.setGeometry(QtCore.QRect(10, 110, 380, 31))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(12)
self.boxname.setFont(font)
self.boxname.setStyleSheet("Entrybox {\n"
"background-color: #595959;\n"
"border:0px;\n"
"color:#ffffff;\n"
"selection-color: #ffffff;\n"
"selection-background-color: #484848;\n"
"border-radius: 15px;\n"
"}\n"
"Entrybox:hover {\n"
"background-color: #636363;\n"
"}\n"
"Entrybox:focus {\n"
"background-color: #636363;\n"
"}")
self.boxname.setAlignment(QtCore.Qt.AlignCenter)
self.boxname.setObjectName("boxname")
self.status = QtWidgets.QLabel(self.centralwidget)
self.status.setGeometry(QtCore.QRect(0, 210, 400, 31))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(15)
self.status.setFont(font)
self.status.setStyleSheet("color:#fff;")
self.status.setAlignment(QtCore.Qt.AlignCenter)
self.status.setObjectName("status")
self.titlelabel = QtWidgets.QLabel(self.centralwidget)
self.titlelabel.setGeometry(QtCore.QRect(10, 250, 36, 31))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(12)
self.titlelabel.setFont(font)
self.titlelabel.setStyleSheet("color:#fff;")
self.titlelabel.setObjectName("titlelabel")
self.boxtitle = Entrybox(self.centralwidget)
self.boxtitle.setGeometry(QtCore.QRect(55, 250, 336, 31))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(12)
self.boxtitle.setFont(font)
self.boxtitle.setStyleSheet("Entrybox {\n"
"background-color: #595959;\n"
"border:0px;\n"
"color:#ffffff;\n"
"selection-color: #ffffff;\n"
"selection-background-color: #484848;\n"
"border-radius: 15px;\n"
"}\n"
"Entrybox:hover {\n"
"background-color: #636363;\n"
"}\n"
"Entrybox:focus {\n"
"background-color: #636363;\n"
"}")
self.boxtitle.setAlignment(QtCore.Qt.AlignCenter)
self.boxtitle.setObjectName("boxtitle")
self.urllabel = QtWidgets.QLabel(self.centralwidget)
self.urllabel.setGeometry(QtCore.QRect(10, 300, 99, 31))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(12)
self.urllabel.setFont(font)
self.urllabel.setStyleSheet("color:#fff;")
self.urllabel.setObjectName("urllabel")
self.boxshorturl = Entrybox(self.centralwidget)
self.boxshorturl.setGeometry(QtCore.QRect(115, 300, 277, 31))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(12)
self.boxshorturl.setFont(font)
self.boxshorturl.setStyleSheet("Entrybox {\n"
"background-color: #595959;\n"
"border:0px;\n"
"color:#ffffff;\n"
"selection-color: #ffffff;\n"
"selection-background-color: #484848;\n"
"border-radius: 15px;\n"
"}\n"
"Entrybox:hover {\n"
"background-color: #636363;\n"
"}\n"
"Entrybox:focus {\n"
"background-color: #636363;\n"
"}")
self.boxshorturl.setAlignment(QtCore.Qt.AlignCenter)
self.boxshorturl.setObjectName("boxshorturl")
self.copybtn = QtWidgets.QPushButton(self.centralwidget)
self.copybtn.setGeometry(QtCore.QRect(160, 340, 81, 41))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(15)
font.setBold(True)
font.setWeight(75)
self.copybtn.setFont(font)
self.copybtn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
self.copybtn.setStyleSheet("QPushButton {\n"
"background-color: #505050;\n"
"border:0px;\n"
"color:#ffffff;\n"
"border-radius:15px;\n"
"}\n"
"QPushButton:hover {\n"
"background-color: #595959;\n"
"}\n"
"QPushButton:pressed {\n"
"background-color: #636363;\n"
"}")
self.copybtn.setObjectName("copybtn")
window.setFocus()
window.setCentralWidget(self.centralwidget)
self.retranslateUi(window)
self.UiSetup()
QtCore.QMetaObject.connectSlotsByName(window)
def retranslateUi(self, window):
_translate = QtCore.QCoreApplication.translate
window.setWindowTitle(_translate("window", "URL Shortener Online"))
self.label.setText(_translate("window", "URL Shortener Online"))
self.gobtn.setText(_translate("window", "Go"))
self.status.setText(_translate("window", ""))
self.titlelabel.setText(_translate("window", "Title:"))
self.urllabel.setText(_translate("window", "Shorten URL:"))
self.copybtn.setText(_translate("window", "Copy"))
def UiSetup(self):
add_hotkey('ctrl + c', self.copylink)
self.boxurl.setPlaceholderText('Enter Long URL')
self.boxname.setPlaceholderText('Enter Alias/Name (Optional)')
self.gobtn.clicked.connect(self.shortenit)
self.copybtn.clicked.connect(self.copylink)
self.titlelabel.setHidden(True)
self.boxtitle.setHidden(True)
self.urllabel.setHidden(True)
self.boxshorturl.setHidden(True)
self.copybtn.setHidden(True)
def showwarning(self,message,title='Error') -> str:
msg = QMessageBox()
msg.setIcon(QMessageBox.Critical)
msg.setText(message)
msg.setWindowTitle(title)
msg.exec_()
def shortenit(self):
url=self.boxurl.text()
if 'http' not in url:
url='http://'+url
name=self.boxname.text()
if name=='':
api_url=f"https://cutt.ly/api/api.php?key=667cc3506cc77adad0b8503f2dfc8a2121930&short={url}"
else:
api_url=f'https://cutt.ly/api/api.php?key=667cc3506cc77adad0b8503f2dfc8a2121930&short={url}&name={name}'
try:
link=get(api_url).json()['url']
except:
self.showwarning('Please check your Internet Connection')
return
self.linkstatus=link['status']
if self.linkstatus==7:
self.status.setText('Done!')
pass
elif self.linkstatus==3:
self.showwarning('Alias/Name is already taken')
return
elif self.linkstatus==2:
self.showwarning('URL is Invalid or not supported')
return
elif self.linkstatus==5:
self.showwarning('Entered Alias/Name in not supported')
return
else:
self.showwarning('Something went wrong!')
return
self.shortlink=link['shortLink']
self.title=link['title']
self.titlelabel.setHidden(False)
self.boxtitle.setHidden(False)
self.urllabel.setHidden(False)
self.boxshorturl.setHidden(False)
self.copybtn.setHidden(False)
self.win.setFixedSize(400,400)
self.boxtitle.setText(self.title)
self.boxshorturl.setText(self.shortlink)
def copylink(self):
try:
copy(self.shortlink)
except:
pass
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
ui = Ui_window()
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
I want to know - how to change text of the button in Kivy (and KivyMD) after pressing some label in the list after the opening MDDropdownMenu.
There is my Main.py
from kivy.app import App
from kivymd.theming import ThemeManager
from kivy.uix.screenmanager import Screen
def toast(text):
from kivymd.toast.kivytoast import toast
toast(text)
class MyScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.menu_items = [
{
"viewclass": "MDMenuItem",
"text": "text%d" % i,
"callback": self.callback,
}
for i in range(1, 3)
]
def change_variable(self, value):
print("\nvalue=", value)
self.VARIABLE = value
print("\tself.VARIABLE=", self.VARIABLE)
def callback(self, *args):
toast(args[0])
class MainApp(App):
title = "KivyMD MDDropdownMenu Demo"
theme_cls = ThemeManager()
def build(self):
return MyScreen()
if __name__ == "__main__":
MainApp().run()
And there is my Main.kv
#:import MDDropdownMenu kivymd.menus.MDDropdownMenu
#:import MDRaisedButton kivymd.button.MDRaisedButton
<MDMenuItem>:
on_release: app.root.change_variable(self.text)
<MyScreen>:
name: 'myscrn'
MDRaisedButton:
size_hint: None, None
size: 3 * dp(48), dp(48)
text: 'MDButton'
opposite_colors: True
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
on_release: MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
Sorry for bad English, and Thanks for help!!!
Give an id to the main button, e.g. id: mainbutton
Update the main button's text in the on_release event of MDMenuItem
Optional: Replace toast(args[0]) with pass in method callback (if you don't want to invoke toast.py)
Snippets - kv file
<MDMenuItem>:
on_release:
app.root.ids.mainbutton.text = self.text
app.root.change_variable(self.text)
<MyScreen>:
name: 'myscrn'
MDRaisedButton:
id: mainbutton
...
Output
I have the problem with the clicking on the dropdown menu labels.
It shows me an error: AttributeError: 'MDMenuItem' object has no attribute 'callback'
This is my main.py
from kivy.app import App
from kivymd.theming import ThemeManager
from kivy.uix.screenmanager import Screen
class MyScreen(Screen):
VARIABLE = ""
menu_items = [
{'viewclass': 'MDMenuItem',
'text': 'text1'},
{'viewclass': 'MDMenuItem',
'text': 'text2'},
]
def change_variable(self, value):
print("\nvalue=", value)
self.VARIABLE = value
print("\tself.VARIABLE=", self.VARIABLE)
class MainApp(App):
title = "KivyMD MDDropdownMenu Demo"
theme_cls = ThemeManager()
def build(self):
return MyScreen()
if __name__ == "__main__":
MainApp().run()
This is an main.kv
#:import MDDropdownMenu kivymd.menus.MDDropdownMenu
#:import MDRaisedButton kivymd.button.MDRaisedButton
<MDMenuItem>:
on_release: app.root.change_variable(self.text)
<MyScreen>:
name: 'myscrn'
MDRaisedButton:
size_hint: None, None
size: 3 * dp(48), dp(48)
text: 'MDButton'
opposite_colors: True
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
on_release: MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
For KivyMD version 0.100.2, you have to provide a callback function.
Snippets
def toast(text):
from kivymd.toast.kivytoast import toast
toast(text)
class MyScreen(Screen):
VARIABLE = ""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.menu_items = [
{
"viewclass": "MDMenuItem",
"text": "text%d" % i,
"callback": self.callback_for_menu_items,
}
for i in range(1, 3)
]
def callback_for_menu_items(self, *args):
toast(args[0])
Output
What I have:
- A dynamic TextWrapper(GridLayout) that includes Images and Labels made from the "description" text out of the SpeciesView.data
- A RecycleView that lets me click through the different texts
The problem is though, that I can't seem to find a way to scroll through the GridLayout (TextWrapper).
I think I am not using the size_hint_y correctly, which should allow the ScrollView to be able to scroll. The reason found here..
The text is always weirdly cut.
So how do I get this ScrollView to work?
from kivy.app import App
from kivy.uix.button import Label
from kivy.lang import Builder
from kivy.properties import BooleanProperty, StringProperty, ObjectProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.gridlayout import GridLayout
from kivy.uix.image import Image
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.scrollview import ScrollView
Builder.load_string("""
<ScreenManagement>:
screen_species: screen_species
ScreenSpecies:
id: screen_species
name: 'screen_species'
<ScreenSpecies>:
species_text: species_text
Label:
pos_hint: {"x": .45, "top": 1}
size_hint: .1, .1
text: "Test"
BoxLayout:
id: species_layout
padding: dp(10)
spacing: dp(10)
orientation: 'horizontal'
SpeciesView:
id: species_list_view
SpeciesText:
id: species_text
name_selected: "" if not species_list_view.name_selected else species_list_view.name_selected
<SpeciesView>:
viewclass: 'SelectableLabel'
name_selected: ""
SelectableRecycleBoxLayout:
orientation: 'vertical'
default_size: None, dp(32)
default_size_hint: .6, None
size_hint: 1, .9
multiselect: False
touch_multiselect: False
<SpeciesText>:
ScrollView:
size_hint_y: None
<SelectableLabel>:
canvas.before:
Color:
rgba: (.05, 0.5, .9, .8) if self.selected else (.5, .5, .5, 1)
Rectangle:
pos: self.pos
size: self.size
<SpeciesLabel>:
text_size: self.size
size_hint_y: None
<SpeciesImage>:
size_hint_y: None
allow_stretch: True
keep_ratio: True
texture_size: dp(20), dp(40)
<TextWrapper>:
minimum_height: self.height
orientation: "vertical"
spacing: 10
cols: 1
size_hint_y: None
""")
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
pass
class SelectableLabel(RecycleDataViewBehavior, Label):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if is_selected:
print("selection changed to {0}".format(rv.data[index]))
rv.name_selected = rv.data[index]['text']
App.get_running_app().root.screen_species.species_text.update(TextWrapper(rv.data[index]["description"]))
else:
print("selection removed for {0}".format(rv.data[index]))
class ScreenSpecies(Screen):
pass
class SpeciesView(RecycleView):
def __init__(self, **kwargs):
super(SpeciesView, self).__init__(**kwargs)
self.data = [
{"text": "Test1", "description": "Test1.textbf\nBla\n |img=image.jpg| Test1.textaf\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla"},
{"text": "Test2", "description": "Test2.text"},
{"text": "Test3", "description": "Test3.text"}
]
class SpeciesText(ScrollView):
def update(self, text_wrapper):
print("Adding TextWrapper {} to SpeciesText ScrollView".format(text_wrapper))
self.clear_widgets()
self.add_widget(text_wrapper)
class SpeciesLabel(Label):
pass
class SpeciesImage(Image):
pass
class TextWrapper(GridLayout):
def __init__(self, text="", **kwargs):
super(TextWrapper, self).__init__(**kwargs)
self.content = self.wrap_text(text)
def wrap_text(self, source):
text = source.split("|")
for i in range(0, len(text)):
if "img=" in text[i]:
self.add_widget(SpeciesImage(source=text[i][4:]))
else:
self.add_widget(SpeciesLabel(text=text[i]))
return text
class ScreenManagement(ScreenManager):
screen_species = ObjectProperty(None)
class TestApp(App):
def build(self):
return ScreenManagement()
test_app = TestApp()
test_app.run()
Thanks as always!
SpeciesText - Using RstDoc
The following example illustrates Kivy RstDcoument. It supports long text, images, and the document is scrollable.
Snippets
kv File
<SpeciesText>:
container: container
orientation: 'vertical'
size_hint: 1, .9
RstDocument:
id: container
Example: SpeciesText - Using RstDoc
main.py
from kivy.app import App
from kivy.uix.button import Label
from kivy.lang import Builder
from kivy.properties import BooleanProperty, ObjectProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.image import Image
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
Builder.load_string("""
<ScreenManagement>:
screen_species: screen_species
ScreenSpecies:
id: screen_species
name: 'screen_species'
<ScreenSpecies>:
species_text: species_text
Label:
pos_hint: {"x": .45, "top": 1}
size_hint: .1, .1
text: "Test"
BoxLayout:
id: species_layout
padding: dp(10)
spacing: dp(10)
orientation: 'horizontal'
SpeciesView:
id: species_list_view
SpeciesText:
id: species_text
name_selected: "" if not species_list_view.name_selected else species_list_view.name_selected
<SpeciesView>:
viewclass: 'SelectableLabel'
name_selected: ""
SelectableRecycleBoxLayout:
orientation: 'vertical'
default_size: None, dp(32)
default_size_hint: .6, None
size_hint: 1, .9
multiselect: False
touch_multiselect: False
<SpeciesText>:
container: container
orientation: 'vertical'
size_hint: 1, .9
RstDocument:
id: container
<SelectableLabel>:
canvas.before:
Color:
rgba: (.05, 0.5, .9, .8) if self.selected else (.5, .5, .5, 1)
Rectangle:
pos: self.pos
size: self.size
""")
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
pass
class SelectableLabel(RecycleDataViewBehavior, Label):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if is_selected:
print("selection changed to {0}".format(rv.data[index]))
rv.name_selected = rv.data[index]['text']
App.get_running_app().root.screen_species.species_text.update(rv.data[index]["description"])
else:
print("selection removed for {0}".format(rv.data[index]))
class ScreenSpecies(Screen):
species_text = ObjectProperty(None)
class SpeciesView(RecycleView):
def __init__(self, **kwargs):
super(SpeciesView, self).__init__(**kwargs)
self.data = [
{"text": "Test1", "description": "./rstDocs/bearwithus.rst"},
{"text": "Test2", "description": "./rstDocs/kvDoc.rst"},
{"text": "Test3", "description": "./rstDocs/sphinxDoc.rst"}
]
class SpeciesText(BoxLayout):
container = ObjectProperty(None)
def update(self, source):
print("Adding TextWrapper {} to SpeciesText ScrollView".format(source))
self.container.source = source
class SpeciesLabel(Label):
pass
class SpeciesImage(Image):
pass
class ScreenManagement(ScreenManager):
screen_species = ObjectProperty(None)
class TestApp(App):
def build(self):
return ScreenManagement()
test_app = TestApp()
test_app.run()
Output: SpeciesText - Using RstDoc
SpeciesText - Using ScrollView+GridLayout+Label+Image
Use ObjectProperty to hook up to the GridLayout. Please refer to the example for details.
Snippets
kv file
<SpeciesText>:
container: container
bar_width: 10
bar_color: 0, 1, 0, 1 # green
bar_inactive_color: 1, 0, 0, 1 # red
effect_cls: "ScrollEffect"
scroll_type: ['bars']
size_hint: (1, None)
# TextWrapper
GridLayout:
id: container
cols: 1
spacing: 10
size_hint_y: None
height: self.minimum_height
Example: SpeciesText - Using ScrollView+GridLayout+Label+Image
main.py
from kivy.app import App
from kivy.uix.button import Label
from kivy.lang import Builder
from kivy.properties import BooleanProperty, StringProperty, ObjectProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.gridlayout import GridLayout
from kivy.uix.image import Image
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.scrollview import ScrollView
Builder.load_string("""
<ScreenManagement>:
screen_species: screen_species
ScreenSpecies:
id: screen_species
name: 'screen_species'
<ScreenSpecies>:
species_text: species_text
Label:
pos_hint: {"x": .45, "top": 1}
size_hint: .1, .1
text: "Test"
BoxLayout:
id: species_layout
padding: dp(10)
spacing: dp(10)
orientation: 'horizontal'
SpeciesView:
id: species_list_view
SpeciesText:
id: species_text
name_selected: "" if not species_list_view.name_selected else species_list_view.name_selected
<SpeciesView>:
viewclass: 'SelectableLabel'
name_selected: ""
SelectableRecycleBoxLayout:
orientation: 'vertical'
default_size: None, dp(32)
default_size_hint: .6, None
size_hint: 1, .9
multiselect: False
touch_multiselect: False
<SpeciesText>:
container: container
bar_width: 10
bar_color: 0, 1, 0, 1 # green
bar_inactive_color: 1, 0, 0, 1 # red
effect_cls: "ScrollEffect"
scroll_type: ['bars']
size_hint: (1, None)
GridLayout:
id: container
cols: 1
spacing: 10
size_hint_y: None
height: self.minimum_height
<SelectableLabel>:
canvas.before:
Color:
rgba: (.05, 0.5, .9, .8) if self.selected else (.5, .5, .5, 1)
Rectangle:
pos: self.pos
size: self.size
<SpeciesLabel>:
size: self.texture_size
size_hint_y: None
<SpeciesImage>:
size_hint_y: None
allow_stretch: True
keep_ratio: True
texture_size: dp(20), dp(40)
""")
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
pass
class SelectableLabel(RecycleDataViewBehavior, Label):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if is_selected:
print("selection changed to {0}".format(rv.data[index]))
rv.name_selected = rv.data[index]['text']
App.get_running_app().root.screen_species.species_text.wrap_text(rv.data[index]["description"])
else:
print("selection removed for {0}".format(rv.data[index]))
class ScreenSpecies(Screen):
species_text = ObjectProperty(None)
class SpeciesView(RecycleView):
def __init__(self, **kwargs):
super(SpeciesView, self).__init__(**kwargs)
self.data = [
{"text": "Test1", "description": "Test1.textbf\nBla\n |img=kivy_logo.jpg| Test1.textaf\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla\nBla"},
{"text": "Test2", "description": "Test2.text"},
{"text": "Test3", "description": "Test3.text"}
]
class SpeciesText(ScrollView):
container = ObjectProperty(None)
def wrap_text(self, source):
print("Adding TextWrapper {} to SpeciesText ScrollView".format(source))
self.container.clear_widgets()
text = source.split("|")
for txt in text:
if "img=" in txt:
self.container.add_widget(SpeciesImage(source=txt[4:]))
else:
self.container.add_widget(SpeciesLabel(text=txt))
class SpeciesLabel(Label):
pass
class SpeciesImage(Image):
pass
class ScreenManagement(ScreenManager):
screen_species = ObjectProperty(None)
class TestApp(App):
def build(self):
return ScreenManagement()
test_app = TestApp()
test_app.run()
Output: SpeciesText - Using ScrollView+GridLayout+Label+Image
When the picture of the woman moves over one of the moving hexagons, a few things happen. I have a sound(police) that is triggered when she touches one of them. The problem is that the sound continues even when she is not on the hexagon even longer. Plus, if she touches the hexagon again the sound is triggered again over the first sound. So now I have a mess of the same sound playing over each other.
I want her to move over a hexagon, the sound is triggered. When she moves off the hexagon the sound instantly stops until she moves over it again.
Here's the code:
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.effects.*;
import ddf.minim.signals.*;
import ddf.minim.spi.*;
import ddf.minim.ugens.*;
Minim minim;
AudioSample police;
color underhex = color(255, 0, 0);
PImage woman;
float headX = 50, headY = 50;
float ss = 0;
float fade=30, fade2=9;
PShape hexagon, trapezoid, trapezoid2;
float[] hspeed = {2.4, 2.8, 3.2, 3.6, 4, 4.4, 4.8};
float[] g = {0, 0, 0, 0, 0, 0, 0};
void setup() {
size(900, 600, P3D);
background(250);
noStroke();
minim = new Minim(this);
police = minim.loadSample("PoliceSiren.mp3", 1024);
hexagon = createShape(GROUP);
PShape trapezoid = createShape(QUAD, 100, 50, 325, 50, 375, 180, 50, 180);
PShape trapezoid2 = createShape(QUAD, 50, 180, 375, 180, 325, 320, 100, 320);
hexagon.scale(0.25);
hexagon.addChild(trapezoid);
hexagon.addChild(trapezoid2);
hexagon.setFill(color(255, 0, 0, 50));
woman = loadImage("woman.png");
}
void draw() {
background(250);
image(woman, headX, headY, 70, 81);
for (int p = 0; p < 5; p++) {
pushMatrix();
translate(g[p], 120*p);
underhex = get(int(g[p])+30, int(120*p)+30);
shape(hexagon, 0, 0);
//ellipse(width/2,height/2,50,50);
popMatrix();
g[p]+=hspeed[p];
if (int(g[p]) > 830 || int(g[p]) < 0) {
hspeed[p] *= -1;
}
if (red(underhex) < 20 && green(underhex) < 20 && blue(underhex) < 20) {
println("she's here"+random(5));
fill(0, 240);
rect(0, 0, 900, 600);
strokeWeight(30);
fill(0, 0, 255, fade);
stroke(0, 0, 255, fade);
ellipse(250, 200, 100, 100);
fill(255, 0, 0, fade);
stroke(255, 0, 0, fade);
ellipse(290, 330, 100, 100);
fill(0, 0, 255, fade);
stroke(0, 0, 255, fade);
ellipse(680, 200, 100, 100);
fill(255, 0, 0, fade);
stroke(255, 0, 0, fade);
ellipse(640, 330, 100, 100);
noStroke();
police.trigger();
fade += fade2;
if (fade<0 || fade>255) {
fade2 *= -1;
}
}
}
if (keyPressed) {
if (keyCode == UP) {
headY-=random(2, 6);
} else if (keyCode == DOWN) {
headY+=random(2, 6);
} else if (keyCode == LEFT) {
headX-=random(2, 6);
} else if (keyCode == RIGHT) {
headX+=random(2, 6);
}
}
}
Try using AudioPlayer instead of AudioSample. It provides isPlaying() which is handy to check if the sound is already playing or not.
e.g.
//at the top
AudioPlayer police;
//in setup()
police = minim.loadFile("PoliceSiren.mp3");
//in draw() instead of police.trigger()
if(!police.isPlaying() || ){
police.play();
}
Update
It sounds like looping is what you're after:
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.effects.*;
import ddf.minim.signals.*;
import ddf.minim.spi.*;
import ddf.minim.ugens.*;
Minim minim;
AudioPlayer police;
color underhex = color(255, 0, 0);
PImage woman;
float headX = 50, headY = 50;
float ss = 0;
float fade=30, fade2=9;
PShape hexagon, trapezoid, trapezoid2;
float[] hspeed = {2.4, 2.8, 3.2, 3.6, 4, 4.4, 4.8};
float[] g = {0, 0, 0, 0, 0, 0, 0};
void setup() {
size(900, 600, P3D);
background(250);
noStroke();
minim = new Minim(this);
//police = minim.loadSample("PoliceSiren.mp3", 1024);
police = minim.loadFile("PoliceSiren.mp3");
hexagon = createShape(GROUP);
PShape trapezoid = createShape(QUAD, 100, 50, 325, 50, 375, 180, 50, 180);
PShape trapezoid2 = createShape(QUAD, 50, 180, 375, 180, 325, 320, 100, 320);
hexagon.scale(0.25);
hexagon.addChild(trapezoid);
hexagon.addChild(trapezoid2);
hexagon.setFill(color(255, 0, 0, 50));
woman = loadImage("woman.png");
}
void draw() {
background(250);
image(woman, headX, headY, 70, 81);
for (int p = 0; p < 5; p++) {
pushMatrix();
translate(g[p], 120*p);
underhex = get(int(g[p])+30, int(120*p)+30);
shape(hexagon, 0, 0);
//ellipse(width/2,height/2,50,50);
popMatrix();
g[p]+=hspeed[p];
if (int(g[p]) > 830 || int(g[p]) < 0) {
hspeed[p] *= -1;
}
if (red(underhex) < 20 && green(underhex) < 20 && blue(underhex) < 20) {
println("she's here"+random(5));
fill(0, 240);
rect(0, 0, 900, 600);
strokeWeight(30);
fill(0, 0, 255, fade);
stroke(0, 0, 255, fade);
ellipse(250, 200, 100, 100);
fill(255, 0, 0, fade);
stroke(255, 0, 0, fade);
ellipse(290, 330, 100, 100);
fill(0, 0, 255, fade);
stroke(0, 0, 255, fade);
ellipse(680, 200, 100, 100);
fill(255, 0, 0, fade);
stroke(255, 0, 0, fade);
ellipse(640, 330, 100, 100);
noStroke();
if(!police.isPlaying()){
police.loop();
}
fade += fade2;
if (fade<0 || fade>255) {
fade2 *= -1;
}
}else{
if(police.isLooping()){
police.pause();
}
}
}
if (keyPressed) {
if (keyCode == UP) {
headY-=random(2, 6);
} else if (keyCode == DOWN) {
headY+=random(2, 6);
} else if (keyCode == LEFT) {
headX-=random(2, 6);
} else if (keyCode == RIGHT) {
headX+=random(2, 6);
}
}
}
Also checkout mute(),unmute(),isMuted(): perhaps you can keep the sound looping but muted and only unmute when the collision happens