I am trying to make my first app in kivy so i copied a basic button code.
class TestApp(App):
def build(self):
btn = Button(text="Press me")
return btn
if name == 'main':
TestApp().run()
however the button doesnt seem to be pressed when i click it with my mouse.
any suggestions how to fix this?
thanks
Try this example.
from kivy.app import App
from kivy.uix.button import Button
class MyButton(Button):
def on_release(self):
print("Button pressed!")
class MyApp(App):
def build(self):
return MyButton(text="Press me!")
MyApp().run()
This should work with python 2 and 3, and Kivy installed. Nothing extra needed.
If this does not work for you, I would try to reinstall Kivy.
Related
Edit: this issue seems to be specific to Qt version 5.12.0. See the answers for more details and for a workaround
I'm trying to implement a drop zone for loading files into my application.
It works when I just show the widget as a top level widget, but it stops working as soon as I include it into another parent widget.
The problem is, altough I'm receiving dragEnterEvent and accepting it, I never see the dropEvent.
This is my widget:
class FileDropZone(qt.QLabel):
"""Target area for a drag and drop operation"""
height = 33
def __init__(self, text="Add file", parent=None):
super().__init__(text, parent)
stylesheet = """
QLabel {
border: 2px dotted #B4BDBA;
qproperty-alignment: AlignCenter;
}
"""
self.setStyleSheet(stylesheet)
self.setAcceptDrops(True)
self.setFixedHeight(self.height)
def dragEnterEvent(self, event):
print("in drag enter event")
if event.mimeData().hasUrls():
print("hasUrls()")
event.acceptProposedAction()
def dropEvent(self, event):
print("in drop event")
urls = event.mimeData().urls()
for url in urls:
print(url.isLocalFile(), url.toLocalFile())
This is how I manage to make it work:
app = qt.QApplication([])
a = FileDropZone()
a.show()
app.exec_()
And this is the example where it does not work (dragEnter works, both prints are properly printed, but dropEvent does not print anything):
app = qt.QApplication([])
a0 = qt.QWidget()
l = qt.QHBoxLayout(a0)
a1 = FileDropZone("drop here", a0)
l.addWidget(a1)
a0.show()
app.exec_()
Any clues about what is broken? Does the parent need to forward the event, and if so, how should I implement it?
It looks like it is a bug which was introduced in Qt 5.12.0 and will be fixed in Qt 5.12.1, see this discussion and this bug report.
In the meantime:
The problem can be worked around by reimplementing dragMoveEvent() and accepting the event there too.
i.e. add e.g. the following method to the FileDropZone class:
def dragMoveEvent(self, event):
print("in drag move event")
if event.mimeData().hasUrls():
print("hasUrls()")
event.acceptProposedAction()
I'm trying to make a simple app to monitor some IO And have a push button screen. I'm getting started on the framework of how the screen would work using kivy as my gui development. I'm wanting to do a lot of label updating based on variables, so the desire to do that has led me into using a .kv file and kivy properties. Admittedly, I know very little about these things it's just what I know from googling and trying to figure out what I need to do.
Regardless, I'm trying to do some basic framework to get started with a .kv file and though my main.py compiles, it does not display any buttons. I'm familiar with adding buttons to a layout done through the python language but I'm looking to do it more in the kivy style. Please help!
Here is my main.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import StringProperty
import random
class YourWidget(Widget):
random_number = StringProperty()
def __init__(self, **kwargs):
super(YourWidget, self).__init__(**kwargs)
self.random_number = str(random.randint(1, 100))
def change_text(self):
self.random_number = str(random.randint(1, 100))
class YourApp(App):
def build(self):
return YourWidget()
if __name__ == '__main__':
YourApp().run()
and here is my your.kv
#:kivy 1.9.2
<YourWidget>:
BoxLayout:
size: root.size
orientation: 'horizontal'
spacing: 10
padding: 10
Button:
id: btn1
text: "Change Text"
on_release: root.change_text()
size_hint: .3, .3
Button:
id: btn2
text: "Exit App"
on_release: App.get_running_app().stop()
size_hint: .3, .3
Label:
id: lbl1
Font_size: 70
text:root.random_number
size_hint: .3, .3
Let me know anything you could assist with. I'm very new to python and extremely new to packages like kivy. Thank you! Another note is currently I am developing this on a monitor and will port to a touch screen later.
Rename your.kv to yourwidget.kv
when drawing graphics on the canvas the class or Widget name of your game must be reflected also in the kivy file. s
I'm writing a simple tool menu for Maya, and I'd like to stick it to the border of model panel (perspective).
from PySide import QtCore, QtGui
from maya import OpenMayaUI as omui
from shiboken import wrapInstance
class TestWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent = self.getMayaWindow())
self.setWindowFlags(QtCore.Qt.Tool | QtCore.Qt.FramelessWindowHint)
self.setFixedSize(100, 100)
panelPtr = omui.MQtUtil.findControl('modelPanel4')
panel = wrapInstance(long(panelPtr), QtGui.QWidget)
position = panel.mapToGlobal(panel.pos())
self.move(position.x(), position.y() + panel.geometry().height() / 2 - self.geometry().height() / 2)
mainLayout = QtGui.QVBoxLayout(self)
button = QtGui.QPushButton('CLOSE')
button.setFixedSize(80, 80)
button.clicked.connect(self.deleteLater)
mainLayout.addWidget(button)
def getMayaWindow(self):
omui.MQtUtil.mainWindow()
ptr = omui.MQtUtil.mainWindow()
return wrapInstance(long(ptr), QtGui.QWidget)
w = TestWidget()
w.show()
The main widget is positioned exactly where I want when it is created (horizontally on the left side of model panel, vertically - in the middle of model panel).
I need to reposition it accordingly when the model panel is resized, but model panel does not emit resized() signal. I'd appreciate any advise.
I've been trying many things to get this working yesterday. I did some additionnal researches today and came to this topic: cgsociety: Creating a floating button inside the viewport
In case of broken link, this is one of the answer:
You can use geometry but there are some issues with triggering
commands based on selection and the undo queue. If you want to go that
route, I would suggest looking into zooHud and zooTriggers (Part of
the zooToolbox)
If you are wanting actual GUI control parented to the viewport, mel
only offers hudslider, hudbutton, and headsUpMessage.
You can also use PyQt and parent in your own custom widgets/layouts or
whatever you want using something like this:
import maya.OpenMayaUI as apiUI import sip
from PyQt4 import QtGui
view = apiUI.M3dView()
apiUI.M3dView.getM3dViewFromModelPanel('modelPanel4', view)
viewWidget = sip.wrapinstance(long(view.widget()), QtCore.QObject)
global myBtn
myBtn = QtGui.QPushButton(viewWidget)
myBtn.setText('testing!')
myBtn.move(100, 100) #Relative to top-left corner of viewport myBtn.show()
You can do anything a full qt widget can do with that, so it's
extremely flexible. but it would require having PyQt installed, which
can be a barrier depending on your tools distribution.
I did a mix of this answer and your code:
from PySide import QtCore, QtGui
from maya import OpenMayaUI as omui
from shiboken import wrapInstance
class CustomQWidget(QtGui.QWidget):
def __init__(self, *args, **kwargs):
QtGui.QWidget.__init__(self, *args, **kwargs)
mainLayout = QtGui.QVBoxLayout(self)
closeButton = QtGui.QPushButton('CLOSE')
closeButton.setFixedSize(80, 40)
closeButton.clicked.connect(self.deleteLater)
helloButton = QtGui.QPushButton('HELLO')
helloButton.setFixedSize(80, 40)
helloButton.clicked.connect(self.printHello)
#Trying to fix glitchy background / Doesn't work, why?
#Is it because layouts don't have background?
p = self.palette()
p.setColor(self.backgroundRole(), QtCore.Qt.red)
self.setPalette(p)
self.setAttribute(QtCore.Qt.WA_StyledBackground, True)
##############################
mainLayout.addWidget(closeButton)
mainLayout.addWidget(helloButton)
def printHello(self):
print "Hello"
view = omui.M3dView()
omui.M3dView.getM3dViewFromModelPanel('modelPanel4', view) #Given the name of a model panel,
#get the M3dView used by that panel. If this fails, then a panel with the given name could not be located.
viewWidget = wrapInstance(long(view.widget()), QtGui.QWidget)
position = viewWidget.mapToGlobal(viewWidget.pos())
w = CustomQWidget(viewWidget)
w.move(0, viewWidget.geometry().height() / 2 - 100 / 2) #Relative to middle-left corner of viewport
w.show()
One of the issue I have it that the background of the widget is glitched:
If anyone knows why and how to fix it, I'll edit my answer with pleasure.
Else, when running this script from Maya's script editor, the widget follows the panel when it is resized.
I did fix such a problem, but not using Python/PyQt.
The problem itself is, that your Qt Widget is there. I have not found a way to make it not paint its background.
My solution was different: I derived from a Qt Layout, pushed all my widgets into that layout and used MQtUtil to get the QWidget of that modelPanel's modelEditor to attach the "real Qt layout" to it.
Heavy caveat that may make Python not suited: Maya doesn't expect "non-Maya" Layouts to be bound to "real-Maya" Widgets like modelEditors. So you need to listen to QEvents and find out when to destroy your layout, so Maya doesn't crash trying.
set autofillbackground True to fix your background painting issue
I have to create one screen in Qt in which I have to show a remote having lots of buttons in it and when user clicks some button on actual remote, corresponding button in the image get highlighted. So what I have done is, I have used QLabel and set the remote image as background image and then I have put small rectangular label for each button and filled them with semi transparent color and when user click button in actual remote label color changes, but by using this method lot of labels are getting used making code looking inefficient, so I was thinking of drawing on QLabel (which has a remote as background image) over buttons.
Can anybody suggest me, which API of Qt should I use, and how to follow up on this?
I believe QGraphics is the correct route for a completely custom graphical interface, but if you want to try something that doesn't require you to change too much of your existing approach, you can do a widget with a custom paint event:
This is written in PyQt but you can easily translate to Qt
from PyQt4 import QtCore, QtGui
class LabelButton(QtGui.QWidget):
clicked = QtCore.pyqtSignal()
def __init__(self, labelStr, pixStr, parent=None):
super(LabelButton, self).__init__(parent)
self.label = labelStr
self.pix = QtGui.QPixmap(pixStr)
def paintEvent(self, event):
super(LabelButton, self).paintEvent(event)
rect = event.rect()
painter = QtGui.QPainter(self)
painter.drawPixmap(rect, self.pix)
pos = (rect.bottomLeft()+rect.bottomRight()) / 2
pos.setY(pos.y()-10)
painter.drawText(pos, self.label)
painter.end()
def mousePressEvent(self, event):
event.accept()
self.clicked.emit()
def handleClick():
print "CLICK"
if __name__ == "__main__":
app = QtGui.QApplication([])
widget = LabelButton("A Text Label", "myImage.png")
widget.resize(600,400)
widget.show()
widget.raise_()
widget.clicked.connect(handleClick)
app.exec_()
This is a rough example. You can get more fine tuned with the drawing of the text. This widget takes a label string, and a picture path, and will paint the picture as the background, and the text as a label. You can do any number of things with this custom widget in both the paint event, and with custom signals and events.
I have used this code to Draw over Image in Label:
Image is loaded in Ui and the Code is as follows In paintevent
void ColorTab::paintEvent(QPaintEvent *e){
ui->lbl_capture_img->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
ui->Lbl_color_tab_WG->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
Cap_Image = QImage(ui->lbl_capture_img->pixmap()->toImage());
Lbl_Image = QImage(ui->Lbl_color_tab_WG->pixmap()->toImage());
QPainter painter_Lbl(&Lbl_Image);
QPainter painter_Cap(&Cap_Image);
QPen pen(Qt::white, 5, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin);
painter_Lbl.setPen(pen);
painter_Cap.setPen(pen);
painter_Lbl.drawPolygon(blinkRect_Lbl);
painter_Cap.drawPolygon(blinkRect_Cap);
ui->lbl_capture_img->setPixmap(QPixmap::fromImage(Cap_Image));
ui->Lbl_color_tab_WG->setPixmap(QPixmap::fromImage(Lbl_Image));
painter_Cap.end();
painter_Lbl.end();
}
I'd like to change the QStyle::PM_TabBarTabHSpace property for a PyQt application. I read the Qt document for QStyle, but I'm not sure how to set this correctly in PyQt.
Non-working code:
style = QStyleFactory.create('Cleanlooks')
style.PM_TabBarTabHSpace = 5 # 5 pixels?
app.setStyle(style)
This code runs, but it doesn't change the padding on the tabbar tabs. I tried using stylesheets to change the tabbar padding, but that ruins the graphics drawing, so that none of the default look-feel stuff gets drawn (I don't want to reimplement all the ui drawing).
I think I might need to use QProxyStyle, but I can't find any examples of how to use this in PyQt4. Edit: It seems that PyQt doesn't have QProxyStyle, as from PyQt4.QtGui import QProxyStyle fails.
Can someone please post an example of changing the value of PM_TabBarTabHSpace? Thanks.
Edit Here is a skeleton code. Changing the PM_TabBarTabHSpace value doesn't do anything. :(
from PyQt4.QtGui import (QApplication, QTabWidget, QWidget,
QStyle, QStyleFactory)
def myPixelMetric(self, option=None, widget=None):
if option == QStyle.PM_TabBarTabHSpace:
return 200 # pixels
else:
return QStyle.pixelMetric(option, widget)
style = QStyleFactory.create('Windows')
style.pixelMetric = myPixelMetric
app = QApplication('test -style Cleanlooks'.split())
# Override style
app.setStyle(style)
tab = QTabWidget()
tab.addTab(QWidget(), 'one')
tab.addTab(QWidget(), 'two')
tab.show()
app.exec_()
QStyle.pixelMetric(...) is built-in class method. You can not set via function pointing. Because, it is in C code. You can test it with adding
def myPixelMetric(self, option=None, widget=None):
print 'Debug, i am calling'
...
in your myPixelmetric function. You need to subclass Style object to achieve this. Here is an example:
class MyStyle(QCommonStyle):
def pixelMetric(self, QStyle_PixelMetric, QStyleOption_option=None, QWidget_widget=None):
if QStyle_PixelMetric == QStyle.PM_TabBarTabHSpace:
return 200
else:
return QCommonStyle.pixelMetric(self, QStyle_PixelMetric, QStyleOption_option, QWidget_widget)
app = QApplication('test -style Cleanlooks'.split())
app.setStyle(MyStyle())
This code snippet will work, but it is ugly. I prefer using stylesheets over manipulating Style.