how to set QTreeView background image with QStyle::StandardPixmap in stylesheet method? - pyqt

i need to change QTreeView background image use QStyle::StandardPixmap with QT stylesheet , i try some method, but it don't work?
The stylesheet look like this, but it not working
QTreeView::branch:closed:adjoins-item {
border-image: url(QStyle::SP_ArrowBack);
}

I suggest quickly uploading QStyle.SP_ArrowBack to the file SP_ArrowBack.png , and then using it in the stylesheet.
import sys
from PyQt5.QtWidgets import QTreeView, QFileSystemModel, QApplication, QStyle
from PyQt5.QtCore import QDir
from PyQt5.QtGui import QIcon
class Tree(QTreeView):
def __init__(self):
QTreeView.__init__(self)
self.setWindowIcon(self.style().standardIcon(QStyle.SP_ArrowBack))
### vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
icon = self.style().standardIcon(QStyle.SP_ArrowBack)
pixmap = icon.pixmap(200, 200, QIcon.Normal, QIcon.On)
_icon = "{}.png".format("SP_ArrowBack")
pixmap.save(_icon, quality = -1)
print("Icon loaded ...")
self.setStyleSheet("""
QTreeWidget {border:None;}
QTreeWidget::item { height: 80px;
color: rgba(255,255,255,255);
}
QTreeView {
alternate-background-color: rgba(135,135,135,255);
background: rgba(145,145,145,255);
}
QTreeView::branch:has-siblings:!adjoins-item {
border-image: url(vline.png) 0;
}
QTreeView::branch:has-siblings:adjoins-item {
border-image: url(branch-more.png) 0;
}
QTreeView::branch:!has-children:!has-siblings:adjoins-item {
border-image: url(branch-end.png) 0;
}
QTreeView::branch:has-children:!has-siblings:closed,
QTreeView::branch:closed:has-children:has-siblings {
border-image: none;
image: url(%s); /* <--- _icon */
}
QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings {
border-image: none;
image: url(branch-open.png);
}
QTreeWidget::item[text="Header1"] {
height: 80px;
}
QTreeWidget::item:children {
height: 40px;
}
""" % _icon)
### ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
model = QFileSystemModel()
model.setRootPath(QDir.currentPath())
self.setModel(model)
self.setRootIndex(model.index(QDir.currentPath()))
model.setReadOnly(True)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Tree()
w.resize(500, 300)
w.show()
sys.exit(app.exec_())

Related

pyqt: why the loaded qss file do not work

I am loading qss file in my project. And I find it do not work.
My qss file is:
QMainWindow
{
font-size: 20px;
background: rgb(255, 0, 0);
}
My code is:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
class Win(QMainWindow):
def __init__(self):
super().__init__()
with open('style.qss', 'r', encoding='utf-8') as file:
str = file.read()
self.setStyleSheet(str)
self.__widget = QWidget()
self.setCentralWidget(self.__widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = Win()
win.show()
app.exec_()
However, the background color of showed window is not red.
-------------------- update --------------------------------------
According to the suggestion of #musicamante, I try that add a overwrited QWidget in the QMainWindow. However, it still do not work.
Try this:
style.qss
font-size: 20px;
background: rgb(255, 0, 0);
or like this:
style.qss
QMainWindow {
font-size: 20px;
background: rgb(255, 0, 0);
}
There are two issues with your code:
when using the curly brackets ({ property: value; }) syntax, the selector is mandatory (see the selector types), otherwise no brackets should be used at all (but that's usually frown upon);
when styling a plain QWidget, the paintEvent() must be overridden (see the related QWidget reference on the stylesheet documentation);
With the given code, the stylesheet syntax should be the following (note the asterisk):
* {
font-size: 20px;
background: rgb(255, 0, 0);
}
When styling a basic QWidget (or a QWidget subclass created in python), the following is also required:
class SomeCustomWidget(QWidget):
# ...
def paintEvent(self, event):
qp = QPainter(self)
opt = QStyleOption()
opt.initFrom(self)
self.style().drawPrimitive(QStyle.PE_Widget, opt, qp, self)
class Win(QMainWindow):
def __init__(self):
# ...
self.__widget = SomeCustomWidget()
self.setCentralWidget(self.__widget)

How to get rid of a white gap between two widget

I would like to code a header banner made of a label and a button.
I almost succeeded, except for a remaining gap between the label and the button.
Do you have any idea how to make it go away?
I'm trying to set the background color on all the widgets at once using a stylesheet.
I also tried to also set it on the container QWidget#container, but it does not work either.
Is there a builtin margin to be removed on QPushButtons, maybe?
class HeaderBannerOneLineCloseButton(qt.QWidget):
icon_path = resources.resource_path("icons/close-white.png")
stylesheet = """
* {
background: %s;
height: 56px;
}
QLabel#title {
color: white;
font-family: Ubuntu-Medium;
font-size: 18px;
padding-left: 31px;
padding-right: 31px;
}
QPushButton#closeButton {
background-origin: content;
background-repeat: no-repeat;
background-position: center middle;
background-image: url("%s");
border: none;
}
""" % (colors.primary1, icon_path)
def __init__(self, parent=None):
super().__init__(parent)
self.setObjectName("container")
self.setStyleSheet(self.stylesheet)
self.setSizePolicy(qt.QSizePolicy(qt.QSizePolicy.Expanding,
qt.QSizePolicy.Fixed))
self.titleLabel = qt.QLabel(self)
self.titleLabel.setObjectName("title")
self.titleLabel.setSizePolicy(qt.QSizePolicy(qt.QSizePolicy.Expanding,
qt.QSizePolicy.Expanding))
self.closeButton = qt.QPushButton(self)
self.closeButton.setObjectName("closeButton")
layout = qt.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.titleLabel)
layout.addWidget(self.closeButton)
self.setLayout(layout)
def setText(self, text):
self.titleLabel.setText(text)
Try it:
from PyQt5 import QtWidgets as qt
from PyQt5 import QtGui as gi
class HeaderBannerOneLineCloseButton(qt.QWidget):
# icon_path = resources.resource_path("icons/close-white.png")
stylesheet = """
* {
background: #2196f3;
height: 56px;
}
QLabel#title {
color: white;
font-family: Ubuntu-Medium;
font-size: 18px;
padding-left: 31px;
padding-right: 31px;
}
/*
QPushButton#closeButton {
background-origin: content;
background-repeat: no-repeat;
background-position: center middle;
background-image: url("D:/_Qt/img/close.png");
border: none;
}
*/
/* ++++++++++++++++++++++++++++++ */
QToolButton{
background:#2196f3;
font-size:11px;
}
QToolButton:hover{
background: #FF00FF;
font-size:11px;
}
""" # % (colors.primary1, icon_path)
def __init__(self, parent=None):
super().__init__(parent)
self.setObjectName("container")
self.setStyleSheet(self.stylesheet)
self.setSizePolicy(qt.QSizePolicy(qt.QSizePolicy.Expanding,
qt.QSizePolicy.Fixed))
self.titleLabel = qt.QLabel("header banner made of a label and a button", self)
self.titleLabel.setObjectName("title")
self.titleLabel.setSizePolicy(qt.QSizePolicy(qt.QSizePolicy.Expanding,
qt.QSizePolicy.Expanding))
# self.closeButton = qt.QPushButton("closeButton", self)
# self.closeButton.setObjectName("closeButton")
close = qt.QToolButton(self) # +++
close.setIcon(gi.QIcon('D:/_Qt/img/close.png')) # +++
close.setMinimumHeight(10) # +++
close.clicked.connect(self.close) # +++
layout = qt.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.titleLabel)
# layout.addWidget(self.closeButton)
layout.addWidget(close) # +++
self.setLayout(layout)
def setText(self, text):
self.titleLabel.setText(text)
if __name__ == "__main__":
import sys
app = qt.QApplication(sys.argv)
win = HeaderBannerOneLineCloseButton()
win.setFixedSize(450, 35) # +++
win.show()
sys.exit(app.exec_())
The simple solution with the least amount of change to my initial code is:
layout.setSpacing(0)
But the previous answer makes a lot of sense. I should have used a toolbutton rather than a push button to have an icon.

How to connect PyQt5 pyqtSlot to QML ListView signal "activated"?

I would like to connect the activated signal from a QML ListView to a pyqtSlot decorated method from my Python3/PyQt5 (5.6) code.
My current approach is to load the QML scene in my code through QQmlApplicationEngine and then use findChild() to get a reference to my ListView.
The problem is, that I can only find the ListView when searching for a QObject like findChild(QObject, 'myList'). But htis object does not give me access to the activated signal, most likely because this signal is only defined for QAbstractItemView and it descendants.
So if I try findChild(QListView, 'myList') the result is None. Therefor I'm not able to get to the activated signal. Is this a bug in PyQt5 or is there another way for me to connect to this signal?
Here is some minimal working example.
list.py:
import sys
from OpenGL import GL
from PyQt5.QtCore import QUrl, QObject
from PyQt5.QtWidgets import QApplication, QListView
from PyQt5.QtQml import QQmlApplicationEngine
# Main Function
if __name__ == '__main__':
# Create main app
app = QApplication(sys.argv)
# Create QML engine
engine = QQmlApplicationEngine(app)
# Load the QML scene from file
engine.load(QUrl('List.qml'))
for root in engine.rootObjects():
node = root.findChild(QListView, 'myList')
if node:
# At this point I would like to connect something to the
# node.activated signal
print(node)
# Execute the application and exit
sys.exit(app.exec_())
List.qml:
import QtQuick 2.0
import QtQuick.Window 2.2
Window {
visibility: Window.FullScreen
visible: true
ListView {
objectName: "myList"
anchors.fill: parent
delegate: Item {
width: parent.width * 0.8
height: 40
Row {
id: row1
Rectangle {
width: 40
height: 40
color: colorCode
}
Text {
text: name
font.bold: true
anchors.verticalCenter: parent.verticalCenter
}
spacing: 10
}
}
model: ListModel {
ListElement {
name: "Grey"
colorCode: "grey"
}
ListElement {
name: "Red"
colorCode: "red"
}
ListElement {
name: "Blue"
colorCode: "blue"
}
ListElement {
name: "Green"
colorCode: "green"
}
}
}
}
You can do that by using QQuickView instead of QQmlApplicationEngine.
I changed your python script to add a new class which inherits from QQuickView, and added a signal to the QML object named "myList".
Moreover, into the QML I removed the Window type for Item type (you can't use Window with QQuickView). If you want to display your application in full screen, you'll have to specify it into MyView class.
In the example, if you click on one of the colored rectangles, the index will be displayed in the console.
list.py:
import sys
from PyQt5.QtCore import QUrl, QObject
from PyQt5.QtWidgets import QApplication, QListView
from PyQt5.QtQuick import QQuickView, QQuickItem
class MyView(QQuickView):
def __init__(self, parent=None):
super().__init__(parent)
# Load the QML scene from file
self.setSource(QUrl('List.qml'))
#connect signal and source
list = self.rootObject().findChild(QQuickItem, 'myList')
list.mySignal.connect(self.mySlot)
def mySlot(self, index):
print(index)
# Main Function
if __name__ == '__main__':
# Create main app
app = QApplication(sys.argv)
# Create QML view
view = MyView()
view.show()
# Execute the application and exit
sys.exit(app.exec_())
List.qml:
import QtQuick 2.0
import QtQuick.Window 2.2
Item {
width: 500
height: 500
ListView {
anchors.fill: parent
id: list
objectName: "myList"
signal mySignal(int index)
delegate: Item {
width: parent.width * 0.8
height: 40
Row {
id: row1
Rectangle {
width: 40
height: 40
color: colorCode
MouseArea{
anchors.fill: parent
onClicked: list.mySignal(index)
}
}
Text {
text: name
font.bold: true
anchors.verticalCenter: parent.verticalCenter
}
spacing: 10
}
}
model: ListModel {
ListElement {
name: "Grey"
colorCode: "grey"
}
ListElement {
name: "Red"
colorCode: "red"
}
ListElement {
name: "Blue"
colorCode: "blue"
}
ListElement {
name: "Green"
colorCode: "green"
}
}
}
}

Styling The Menu Bar in PyQT4

I am finishing up my application and I can't figure up how to change the MenuBar in pyqt4. I am using a dark and gray theme, and on windows the menu bar is white, and I would like it to be dark like the rest of the app. How do I change the background color of QMenu or QMenuBar colors In PyQt4. I have been able to change the drop downs, but the top bar with File | Tools | Help stays white. Properties I tried changing:
background-color: # Doesn't seem to do anything
color: # Only changes the text color not the background
alternate-background-color: # Doesn't seem to do anything
Maybe I just haven't found the right property to assign the background color to match the rest of the app, a little help? Thanks!
It looks fine on my PC.
class SubMenu(QMenuBar):
def __init__(self, parent=None):
super(SubMenu, self).__init__(parent)
self.addAction("File")
self.addAction("View")
self.setStyleSheet("""QMenuBar {
background-color: blue;
}""")
self.resize(320, 240)
if __name__ == '__main__':
app = QApplication(sys.argv)
m = SubMenu()
m.show()
app.exec_()
Style sheet with Items
class SubMenu(QMenuBar):
def __init__(self, parent=None):
super(SubMenu, self).__init__(parent)
self.addAction("File")
self.addAction("View")
self.setStyleSheet("""QMenuBar {
background-color: blue;
}
QMenuBar::item {
background: blue;
}""")
self.resize(320, 240)
if __name__ == '__main__':
app = QApplication(sys.argv)
m = SubMenu()
m.show()
app.exec_()
Hope this comment may help others someday.
PySide2, Python 3+
self.saveFile_action = QAction("&Save", self)
self.saveFile_action.setShortcut("Ctrl+S")
self.saveAllFile_action = QAction("Save &All", self)
self.saveAllFile_action.setShortcut("Ctrl+Shift+S")
self.menuBar = QMenuBar(self)
self.menuBar.setStyleSheet(
"""
QMenuBar
{
background-color: #333399;
color: #999;
}
QMenuBar::item
{
background-color: #333399;
color: #999;
}
QMenuBar::item::selected
{
background-color: #3399cc;
color: #fff;
}
QMenu
{
background-color: #3399cc;
color: #fff;
}
QMenu::item::selected
{
background-color: #333399;
color: #999;
}
"""
)
self.fileMenu = QMenu("&File", self.menuBar)
self.exportSubmenu = QMenu("&Export", self.fileMenu)
self.fileMenu.addSeparator()
self.fileMenu.addAction(self.saveFile_action)
self.fileMenu.addAction(self.saveAllFile_action)
self.fileMenu.addSeparator()
self.fileMenu.addAction(self.exportSubMenu.menuAction())
self.settinsMenu = QMenu("&Settings", self.menuBar)
self.helpMenu = QMenu("&Help", self.menuBar)
self.menuBar.addAction(self.fileMenu.menuAction())
self.menuBar.addAction(self.settingsMenu.menuAction())
self.menuBar.addAction(self.helpMenu.menuAction())

About JavaFx Layout

I have a question about javafx layout, following is my code you can run the code directly:
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.control.TextBox;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.Group;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
/**
* #author Administrator
*/
var headerHeight: Number = 50;
var header: Group = Group {
var searchBox: HBox;
content: [
Rectangle {
width: bind scene.width;
height: bind headerHeight;
fill: Color.BLUE
},
searchBox = HBox {
spacing: 10
layoutY: bind (headerHeight - searchBox.layoutBounds.height) / 2;
layoutX: bind scene.width - searchBox.layoutBounds.width - 20;
var textBox: TextBox;
content: [
textBox = TextBox {
promptText: "please input search key"
columns: 20
selectOnFocus: true
}, Button {
text: "search"
strong: true
action: function() {
println("Button clicked");
}
}]
}
]
}
var rect = Rectangle {
width: bind 400;
height: bind 80;
fill: Color.YELLOW
}
var footerHeight: Number = 50;
var footer: Group = Group {
var bounds: Rectangle;
content: [
bounds = Rectangle {
width: bind scene.width;
height: bind footerHeight;
fill: Color.RED
}
]
}
var scene: Scene = Scene {
content: [
VBox {
content: [
header,
rect,
footer
]
}
]
}
function run() {
Stage {
scene: scene
}
}
The scene's height is not normal. Footer's height is 50, but seems only about 30.
what's wrong, any advise?
Thanks.
For some reason the Scene isn't resizing to fit the full contents. I'm not sure why, but you may be able to work around this by setting scene.height = headerHeight + 80 + footerHeight.
Try binding to the Stage instead of Scene.

Resources