Create new components on an inherited window in pyqt5 - python

I'm working on a small GUI made in PYQT5. I have a main window with a couple of buttons which open new windows. One of these windows has an embedded matplotlib plot and 2 buttons.
So, from this existing window called "PlotWindow" I want to create a new window called "DynamicPlotWindow" but add more elements (Comboboxes, buttons, methods, etc.). In other words, I want to reuse existing windows and put more components on them. I´m able to create new DynamicPlotWindow windows, but the new components added to it aren´t visible.
Based on this question: PyQt5 Making a subclass widgets the definition of both clases is as follows:
class PlotWindow(QMainWindow): #Matplotlib embeded + 2 buttons
def __init__(self, parent):
super(QMainWindow, self).__init__(parent)
self.width = 1000
self.height = 540
self.setGeometry(10, 10, self.width, self.height)
...
self.show()
...
class DynamicPlotWindow(PlotWindow):
def __init__(self, parent):
super(PlotWindow, self).__init__(parent)
self.btn = QPushButton("Test") # -> Not visible
self.btn.resize(120,30)
self.btn.move(600,800)
...
self.show()
My question is what am I doing wrong here? Is it possible to do it?
Best,

Your code has the following errors:
The botton is not a child of the window so it will not be shown, the solution is to pass it to self as parent
The window has a size of 1000x540 but you want to place the button in the position (600,800) that is clearly outside the height: 800> 540.
The solution is:
self.btn = QPushButton("Test", self)
self.btn.resize(120,30)
self.btn.move(600, 200) # change y coordinate

Related

Qt with Windows 10 transparent widget not working

I am working on put some drawings over some child widgets in a window. So I came up with a transparent overlay widget, making its background transparent, putting it on top of the other windows, painting directly on it. It all worked fine on Mac. However, this overlay widget just won't show up in Windows 10. Here are some code for creating this overlay transparent widget:
class OverlayWidget(QWidget):
def __init__(self, x, y, width, height):
super(OverlayWidget, self).__init__()
self.setWindowFlags( Qt.FramelessWindowHint | Qt.Widget | Qt.WindowStaysOnTopHint | Qt.TransparentMode)
self.setAttribute(Qt.WA_TranslucentBackground)
self.org_x = x
self.org_y = y
self.window_width = width
self.window_height = height
self.setGeometry(self.org_x, self.org_y, self.window_width, self.window_height)
self.setMouseTracking(True)
self.setCursor(Qt.BlankCursor)
Once I set the WA_TranslucentBackground attribute, nothing shows up, even the mouse cursor won't change, which means this widget probably wasn't even loaded. Any suggestions?
EDIT:
It seems that this is related to how this widget is added to its parent. If I create a layout and add it to the layout and then set its parent layout as the one I just created, it did show up. However, doing this contradicts with my purpose of overlaying it on top of another existing layout.
But if I just created this widget by passing the parent widget into it constructor, it doesn't work in Windows, but works in Mac.
This is quite annoying.

How to show Qt.Tool window with minimize/maximize windows controls?

I have...
class ToolWindow(QtWidgets.QMainWindow):
"""Generic window to be used as non-modal tool
Usage:
tool_win = ToolWindow()
layout = QtWidgets.QHBoxLayout()
button = QtWidgets.QPushButton('hello')
layout.addWidget(button)
tool_win.setup(layout)
button.released.connect(lambda: print('hello'))
tool_win.show()
"""
def __init__(self):
super(ToolWindow, self).__init__()
def setup(self, layout,
window_title='Untitled', object_name=None, tool=True):
"""Setup tool window"""
if tool:
self.setWindowFlags(QtCore.Qt.Tool)
self.widget = QtWidgets.QWidget()
self.widget.setLayout(layout)
self.setCentralWidget(self.widget)
self.setWindowTitle(window_title)
def closeEvent(self, event):
"""Delete object when closed"""
self.deleteLater()
However, I wish to add the typical maximize and minimize window controls to the window. I've attempted to add the following to the ToolWindow class without success (the tool window still doesn't show the maximize/minimize window controls):
self.setWindowFlags(self.windowFlags() |
QtCore.Qt.WindowSystemMenuHint |
QtCore.Qt.WindowMinMaxButtonsHint)
Is it possible to add these controls to a tool window?
Alternatively, can I create a non-modal window but which always sits atop my parent application and which shows the maximize/minimize window controls?
Please note, I don't want this tool window staying on top of ALL windows on my system. I only want it to always stay on top of my application.
You should be able to just use the QMainWindow class without any flags. As long as the tool window is a child of the primary application window, it will stay on top of it (but not windows from other applications, like it would if you set the "Window Stays On Top" flag).
You'll need to change your __init__ to accept parent arguments
def __init__(self, parent):
super(ToolWindow, self).__init__(parent)
If you have multiple Tool Windows and you want them to stay on top in a specific order, you can call my_tool_window.raise_() to bring it to the top of the z-order.
Qt ships with a window flags example. You may want to check that out to see how the different flags affect the window display and behavior.

StackLayout changes size automagically in kivy framework

I am using Win7, Eclipse, python 2.7 + kivy framework for developing a openGL app.
I am trying to check some collision points(x, y) of a Widget on a mouse click. I create a layout with a specific size, but when entering the on_touch_down(mouse click) callback the layout size is strangely changed(here is the problem). Let me show you my code:
class PlayScreen(Screen):
layout = None
def __init__(self):
self.layout = StackLayout(size=(Types.SCREEN_SIZE_WIDTH, 100))
#then I create widgets inside the layout:
self.lblScore = Label(text='SCORE:', size_hint=(.1, .1))
self.lblScoreValue = Label(text='0', size_hint=(.1, .1))
.....
self.layout.add_widget(self.lblScore)
self.layout.add_widget(self.lblScoreValue)
#here the debugger shows me self.layout size to be(800, 100)
#and then I want to test if I click on the self.layout:
def on_touch_down(self, touch):
bCanAddTower = True
if self.layout.collide_point(touch.x, touch.y) == True:
print "colision with menu"
#here self.layout has size=(800, 600)(here is the problem) the entire window size, and of course I get into collision all the time.
Does anybody have any idea why the size of the self.layout changes in on_touch_down method?
The initial size is because you instantiate the widget with that size, so all the code you run immediately aftewards sees this value. However, its parent widget is a Screen which is a Layout class (specifically a RelativeLayout) that automatically resizes its children to fill itself unless you set some other options. This automatic resizing only takes place after its __init__ (but before the next frame), which is why on_touch_down, or any other method, will see the new size.
In this case, you can add size_hint=(None, None) to the self.layout instantiation. This simply tells the parent Screen not to manually control its size, so it will remain as you have set it.
In the longer term, you may want to work with some proportional size setting rather than a fixed value, as a totally fixed size won't appear the same way on different screen sizes, pixel densities etc.

How to add scrollbars in PyQt4 WITHOUT with absolute positioning

I'm creating an interface in PyQt4, and I am in need of scrollbars. My interface uses absolute positioning. I have looked a other treads for adding scrollbars, but the only answers given are to those interfaces without a layout (such as VBoxLayout, Grid Layout, etc).
Please take a look at my code. How could I add a scrollbars (horizontal and vertical) to this interface?
The full code wouldn't format properly on here, so I'll link to this pastebin
http://pastebin.com/hEH4R534
Here is the base of the interface (a 1500px by 1000px window)
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(100,100,1500,1000)
def main():
import sys
app = QtGui.QApplication(sys.argv)
window = Example()
window.show()
sys.exit(app.exec_())
main()
The question is... How would I modify the code above so I have horizontal and vertical scrollbars?
Only widgets that inherit from QAbstractScrollArea can have scroll bars. You could place one of those widgets inside your widget, and then place other widgets inside that widget. Or, just have your widget inherit from QScrollArea instead of QWidget.
By default, scroll bars will only appear when necessary to display hidden child widgets. You can force scroll bars to appear by setting the scroll bar policy for the widget.
from PyQt4.QtCore import Qt
...
def initUI(self):
self.setGeometry(100, 100, 1500, 1000)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

PyQt4: How to reorder child widgets?

I want to implement a GUI program like the blueprint editor in the Unreal game engine with PyQt4. Here is an example of the blueprint editor:
First I create a simple container widget to place all the components(The rectangles). Then I use the QPainterPath widget to draw lines to connect the components. Since the users can place the components wherever they want by drag and drop, I choose absolute positioning in my container widget. Here is the sample code:
class Component(QtGui.QWidget):
"""A simple rectangle."""
def __init__(self, type_, parent=None):
super(Component, self).__init__(parent)
...
class BezierPath(QtGui.QWidget):
def __init__(self, start, end, parent=None):
super(BezierPath, self).__init__(parent)
self.setMinimumSize(300, 500)
self._start = start
self._end = end
self._path = self._generate_path(self._start, self._end)
self.setMinimumSize(
abs(start.x()-end.x()), abs(start.y()-end.y()))
def _generate_path(self, start, end):
path = QtGui.QPainterPath()
path.moveTo(start)
central_x = (start.x()+end.x())*0.5
path.cubicTo(
QtCore.QPointF(central_x, start.y()),
QtCore.QPointF(central_x, end.y()),
end)
return path
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
pen = QtGui.QPen()
pen.setWidth(3)
painter.setPen(pen)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.drawPath(self._path)
painter.end()
class Container(QtGui.QWidget):
def add_component(self, component_type, position):
component = Component(component_type, self)
component.move(position)
def add_connection(self, component_a, component_b):
bezier_path = BezierPath(component_a.pos(), component_b.pose(), self)
The problem is I want to lines show underneath the components, but the components are created first. Is there a way I can reorder the child widgets of the Container of should I use a better way to organize the components?
I found a solution for reordering the child widgets myself. I'll mark this answer as accepted for now. It's not a perfect solution so if there is a better answer I will accept it then. Anyway here is the solution:
In qt4 the widget has a method raise_(), here I quote:
to raises this widget to the top of the parent widget's stack. After
this call the widget will be visually in front of any overlapping
sibling widgets.
So if you want to reorder all your widgets, first you keep the references of all the child widgets in you own list or what container you choose. Reorder all the widgets in you own container, then call raise_() for each widget in reverse order.

Categories