I am currently working on a small application to do with arranging music lessons and am trying to add a background image. When I add an image it also repeats the image in the menu bar and toolbar. How can I stop this from happening?
Thanks in advance!
import sys
from PyQt4 import QtGui
class windowMain(QtGui.QMainWindow):
def __init__(self):
super(windowMain, self).__init__()
self.initUI()
def initUI(self):
#Layout of window
self.resize(700, 500) #Maximizing main window
self.center()
self.setWindowTitle('Lesson Planner') #Setting window title
self.setStyleSheet("border-image: url(p.jpg);")
self.show() #Showing the window
If you don't specify which widget(s) the stylesheet applies to, it will cascade to all child widgets (i.e. just like CSS). So, as with CSS, you need to use the right selector syntax to apply the background image to the appropriate widget.
For you example, one way to do that would be to set the objectName for the central widget of the main window, and then use that name in the selector:
def initUI(self):
self.centralWidget().setObjectName('CentralWidget')
self.setStyleSheet("""
#CentralWidget { background-image: url(./image.png) }
""")
Related
I am trying to make a svg widget load inside my Krita docker to act as a cursor. Krita is a painting program and it uses python and PyQt5 to load up plugins. I made a blank docker with the bare minimum for it to load. If anything is add will be in the Area marked with "Testing".
However my SVG load method seems not to be working when compared with other references, and i think it might be the path to the frame itself as I try to place the viewer that I loaded.
# Import Krita
from krita import *
from PyQt5 import QtWidgets, QtCore, QtGui, QtSvg, uic
import os.path
from PyQt5 import QtWidgets, QtSvg
# Set Window Title Name
DOCKER_NAME = "Blank"
# Create Docker
class BlankDocker(DockWidget):
"""
Comments
"""
# Initialize the Dicker Window
def __init__(self):
super(BlankDocker, self).__init__()
# Window Title
self.setWindowTitle(DOCKER_NAME)
# Widget
self.window = QWidget()
self.layout = uic.loadUi(os.path.dirname(os.path.realpath(__file__)) + '/blank.ui', self.window)
self.setWidget(self.window)
# TESTING###################################################################################
self.viewer = QtSvg.QSvgWidget()
self.viewer.load('C:/Users/EyeOd/AppData/Roaming/krita/pykrita/blank/Notes/cursor_lmb.svg')
self.viewer.setGeometry(QtCore.QRect(0,0,200,200))
self.layout.frame.addWidget(self.viewer) #??
############################################################################################
# Change the Canvas
def canvasChanged(self, canvas):
pass
The area of interest of the *.UI file I load is the QFrame = "frame" in which I want to place the widget inside to move around inside.
http://pasteall.org/pic/show.php?id=b7083dbb5e13adafcddb9ee9fdfa8fcd
QFrame doesn't have any method called addWidget so you should have an exception. So if you want to place the QSvgWidget in the QFrame you have 2 alternatives:
Set as parent of QSvgWidget to QFrame.
self.viewer = QtSvg.QSvgWidget(self.window.frame)
self.viewer.load('C:/Users/EyeOd/AppData/Roaming/krita/pykrita/blank/Notes/cursor_lmb.svg')
self.viewer.setGeometry(QtCore.QRect(0, 0, 200, 200))
Use a layout:
self.viewer = QtSvg.QSvgWidget()
self.viewer.load('C:/Users/EyeOd/AppData/Roaming/krita/pykrita/blank/Notes/cursor_lmb.svg')
lay = QVBoxLayout(self.window.frame)
lay.addWidget(self.viewer)
Note: If you use self.layout = uic.loadUi(..., self.window) then you will see that self.layout is the same self.window object so to avoid confusion it is advisable to use uic.loadUi(..., self.window)
I'm getting this weird result when using QMenuBar I've used this exact code before for the QMenuBar and it worked perfectly. But it doesn't show more than 1 QMenu
This is my code:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
from functools import partial
class MainMenu(QWidget):
def __init__(self, parent = None):
super(MainMenu, self).__init__(parent)
# background = QWidget(self)
lay = QVBoxLayout(self)
lay.setContentsMargins(5, 35, 5, 5)
self.menu()
self.setWindowTitle('Control Panel')
self.setWindowIcon(self.style().standardIcon(getattr(QStyle, 'SP_DialogNoButton')))
self.grid = QGridLayout()
lay.addLayout(self.grid)
self.setLayout(lay)
self.setMinimumSize(400, 320)
def menu(self):
menubar = QMenuBar(self)
viewMenu = menubar.addMenu('View')
viewStatAct = QAction('Dark mode', self, checkable=True)
viewStatAct.setStatusTip('enable/disable Dark mode')
viewMenu.addAction(viewStatAct)
settingsMenu = menubar.addMenu('Configuration')
email = QAction('Set Email', self)
settingsMenu.addAction(email)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = MainMenu()
main.show()
sys.exit(app.exec_())
Result:
I am aware that I am using QWidget when I should be using QMainWindow But is there a workaround???
(I apologize in advance for the terrible quality of the image, there is no good way to take a picture of a QMenuBar)
The problem is that with a QWidget you are not using the "private" layout that a QMainWindow has, which automatically resizes specific children widgets (including the menubar, the statusbar, the dock widgets, the toolbars and, obviously, the "centralWidget").
Remember that a QMainWindow has its own layout (which can't and shouldn't be changed), because it needs that specific custom layout to lay out the aforementioned widgets. If you want to set a layout for the main window, you'll need to apply it to its centralWidget.
Read carefully how the Main Window Framework behaves; as the documentation reports:
Note: Creating a main window without a central widget is not supported. You must have a central widget even if it is just a placeholder.
In order to work around that when using a basic QWidget, you'll have to manually resize the children widgets accordingly. In your case, you only need to resize the menubar, as long as you have a reference to it:
def menu(self):
self.menubar = QMenuBar(self)
# any other function has to be run against the *self.menubar* object
viewMenu = self.menubar.addMenu('View')
# etcetera...
def resizeEvent(self, event):
# calling the base class resizeEvent function is not usually
# required, but it is for certain widgets (especially item views
# or scroll areas), so just call it anyway, just to be sure, as
# it's a good habit to do that for most widget classes
super(MainMenu, self).resizeEvent(event)
# now that we have a direct reference to the menubar widget, we are
# also able to resize it, allowing all actions to be shown (as long
# as they are within the provided size
self.menubar.resize(self.width(), self.menubar.height())
Note: you can also "find" the menubar by means of self.findChild(QtWidgets.QMenuBar) or using the objectName, but using an instance attribute is usually an easier and better solution.
Set minimum width
self.setMinimumSize(320,240)
I had an application that contained a lot of widgets with stylesheet on them, However, I did not add any layout to interface, It neither had central widget included, But the application was running without any problems.
However, whenever i tried to resize the application (scaling it down) the widgets would not scale, of course.
I had an little research (Because i could not find anything else related to my problem) and i found this on Qt Documentation, stylesheet reference:
"The actual image that is drawn is determined using the same algorithm as QIcon (i.e) the image is never scaled up but always scaled down if necessary."
How can i make stylesheet scale down with window? (If stylesheet has background image on)
For example i have button with stylesheet:
btn = QtGui.QPushButton(self)
btn.move(0, 0)
btn.setObjectName('btn)
btn.setStyleSheet("#btn {background-image: url(':/images/somepicture.png'); border: none; }")
How can i make this button scale down with window, Can i achieve this without layouts? If not how can i do it with layouts? (without it limiting too much)
If you add the button as the central widget to a QMainWindow it should automatically adjust it's size to fit the available space. However, to get the button image to scale, you need to set the image as a border-image stylesheet property (a little strange). A working example for PyQt4:
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
btn = QtGui.QPushButton(self)
btn.setStyleSheet("border-image: url('somepicture.png');") # Scaled
#btn.setStyleSheet("background-image: url('somepicture.png');") # Not scaled
self.setCentralWidget(btn)
self.show()
app = QtGui.QApplication([])
window = MainWindow()
app.exec_()
Note that you don't need to set an id (objectName) to assign the CSS to a specific widget, you can simply pass in the CSS rule via .setStyleSheet().
You cannot set a layout on QMainWindow as it already has a complex layout system to accommodate docking widgets and toolbars. Therefore, if you want to use a layout to add more than one widget to the window, you need to use a container widget to hold it. The following working example demonstrates this:
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
w = QtGui.QWidget() # container widget
l = QtGui.QVBoxLayout() # your layout
w.setLayout(l) # set the layout on your container widget
btn = QtGui.QPushButton(self)
btn.setStyleSheet("border-image: url('somepicture.png');")
label = QtGui.QLabel('Hello!')
l.addWidget(btn) # add your widget to the layout
l.addWidget(label) # add the label to the layout
self.setCentralWidget(w) # add the container widget to the QMainWindow
self.show()
app = QtGui.QApplication([])
window = MainWindow()
app.exec_()
If you want to be able to position widgets absolutely, rather than adding them to a layout (which will control their size/position) you can pass the parent element (relative to which x,y coords are taken) when creating it:
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
w = QtGui.QWidget() # container widget
btn = QtGui.QPushButton(w)
btn.move(100,100)
btn.setStyleSheet("border-image: url('somepicture.png');")
self.setCentralWidget(w) # add the container widget to the QMainWindow
self.show()
app = QtGui.QApplication([])
window = MainWindow()
app.exec_()
But positioning a widget absolutely like this loses you the ability to auto-scale it to fit the parent widget. If you just want some padding/spacing around the element in the window, take a look at .setContentsMargins on the QLayouts, e.g. l.setContentsMargins(50,50,50,50) will put a 50px margin around the button.
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). In order to allow the user place the rectangles wherever they want(by drag & drop), I can't place my widgets in a layout. Then when the content of the rectangle is changed, the rectangle widget can't auto adjust the size itself.
Following is an example code:
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
class ChangeableChild(QtGui.QWidget):
def __init__(self, parent=None):
super(ChangeableChild, self).__init__(parent)
self.setLayout(QtGui.QVBoxLayout())
def addWidget(self, widget):
self.layout().addWidget(widget)
class MainWidget(QtGui.QWidget):
def __init__(self, child, parent=None):
super(MainWidget, self).__init__(parent)
child.setParent(self)
def main():
app = QtGui.QApplication(sys.argv)
changeable_child = ChangeableChild()
button = QtGui.QPushButton("Add label")
changeable_child.addWidget(button)
win = MainWidget(changeable_child)
win.show()
button.clicked.connect(
lambda: changeable_child.addWidget(QtGui.QLabel("A label.")))
app.exec_()
if __name__ == "__main__":
main()
When I hit "Add label" button to add a new label. The size of ChangeableChild wouldn't change automatically. If I put the ChangeableChild in a layout, it's all good.
So is there a way to auto adjust my widget when it's not in a layout? Or is there a way I can place my widget in a layout and still can place it in a absolute position?
im trying to find out in PyQT how can i set the Mousewheel event?
i need it so i can attach it to the Qscroll area
the code im using is working fine. but the size is hardcoded. i need it to somehow dynamically adjust depending on how the wheel(on the mouse) is used.. like when i slide the mouse wheel up. the height of my frame extends(like 50pixels per tick) and vise versa.
self.scrollArea = QtGui.QScrollArea()
#set the parent of scrollArea on the frame object of the computers
self.scrollArea.setWidget(self.ui.Main_Body)
self.scrollArea.setWidgetResizable(True)
#add the verticalLayout a object on PYQT Designer (vlayout is the name)
#drag the frame object of the computers inside the verticalLayout
#adjust the size of the verticalLayout inside the size of the frame
#add the scrollArea sa verticalLayout
self.ui.verticalLayout.addWidget(self.scrollArea)
self.ui.Main_Body.setMinimumSize(400, 14000)
the last part is what i want to enhance. i dont want it to be hardcoded into a 14000 value.
thanks to anyone who will help. and i hope that the given sample code can also help others in need.
)
I might be a little confused on your question, but here's an example on how to get access to wheel events that resize your window. If you're using a QScrollArea I don't know why you would want to do this though.
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class Main(QWidget):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
layout = QHBoxLayout(self)
layout.addWidget(Scroll(self))
class Scroll(QScrollArea):
def __init__(self, parent=None):
super(Scroll, self).__init__(parent)
self.parent = parent
def wheelEvent(self, event):
super(Scroll, self).wheelEvent(event)
print "wheelEvent", event.delta()
newHeight = self.parent.geometry().height() - event.delta()
width = self.parent.geometry().width()
self.parent.resize(width, newHeight)
app = QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
If you look at the documentation for QScrollArea you'll see the line of inherited from the QWidget class which has a function called wheelEvent. You can put that in and overwrite the inherited function.