Painting QTreeViewItem expand buttons and sibling/child lines - python

I am using a QTreeView and a QItemDelegate to reimplement most of the paint routine. However, the expand/collapse buttons and the sibling/child lines are drawn automatically by some other paint routine.
What is drawing them, and how can I control it?
EDIT:
Right now, Qt draws a QTreeView item in this order:
[Expand button] -- [Checkbox] -- [Rest of treeitem stuff]
I want to draw it in this order:
[Checkbox] -- [Expand button] -- [Rest of treeitem stuff]
The problem is that all my painting in the QItemDelegate is to the right of the Expand Button.

You can change those using a style sheet. This is from the Customizing QTreeView example in the style sheet reference:
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(branch-closed.png);
}
QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings {
border-image: none;
image: url(branch-open.png);
}
where the png filenames are the images you want to use.

The rows are painted by QTreeView.drawRow, the branches and expand icons are drawn in drawBranches. Reimplement it to do nothing and you'll get rid of any automatically drawn stuff:
def drawBranches(self,painter,rect,index):
pass
Unfortunately simply exchanging the buttons and checkboxes during painting won't work, because then clicks on the checkbox will trigger the button and vice versa.

Related

How To Make Scrollbar Handle Clickable After Styling?

I'm making a GUI for a client and I'm using Qt for Python 3.6 (PySide2, not PyQt). I have a QTableWidget that reads a bunch of data, which makes the scrollbar appear. My client wants a custom GUI style, so I've been using Qt's setStyleSheet() functions.
I've run into an issue where setting the style on the scrollbar to remove the arrow buttons resizes the handle (as you'd expect) and allows it to move over the area where the arrow buttons used to be. However, if my mouse is in those areas, I can't click on the scrollbar.
The green circles are where the arrow buttons would typically be, the red bar is my scrollbar handle. If my mouse is in the green circles, I can't click on the scrollbar's handle. This becomes a big problem if the scrollbar would become smaller than the button sizes, meaning I'd have to use the scroll wheel to get it out of the area before being able to click on it. While I can fix that issue by giving the handle a minimum height/width, it's also a pretty bad user experience when you can't click certain areas of the scrollbar...
Here is my style sheet:
* {
color:white;
}
QWidget {
background-color:#333;
}
QGroupBox, QGroupBox QLabel {
background-color:#4c4c4c;
}
QLineEdit {
background-color:white;
color:black;
}
QComboBox, QPushButton {
background-color:maroon;
}
QToolTip {
border:3px solid maroon;
padding:5px;
font-size:16px;
background-color:#333;
}
QTableWidget {
color:black;
background-color:white;
alternate-background-color:#ffd6d6;
gridline-color:#4c4c4c;
selection-background-color:maroon;
}
QHeaderView::section {
padding:3px;
text-align:center;
}
QScrollBar::handle {
background-color:maroon;
border-radius:6px;
border: 2px solid #d10000;
min-width:25px;
min-height:25px;
}
QScrollBar::left-arrow:horizontal, QScrollBar::right-arrow:horizontal,
QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
border: none;
background: none;
color: none;
}
QScrollBar::add-line, QScrollBar::sub-line {
border:none;
background-color:none;
}
I'm pretty new to using Qt style sheets, so I'm wondering if I'm not missing something. Most answers I've managed to find only say to do what I've already done in the 3 last styles. Does anyone know what the issue might be?
After putting it aside for about a week, I've finally had to sit down and fix this issue.
For those with the same problem who're also scratching their heads at the answer to this question: Hide QScrollBar arrows, I've found a pretty obvious fix, now that I think about it.
While the following style sheet does in fact hide the arrow buttons, it does not remove them. Which is obvious in practice, since with further testing, clicking the areas still moved the handle as if I were clicking on the arrow buttons.
QScrollBar::left-arrow:horizontal, QScrollBar::right-arrow:horizontal,
QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
border: none;
background: none;
color: none;
}
QScrollBar::add-line, QScrollBar::sub-line {
border:none;
background-color:none;
}
The solution is pretty simple: The arrow buttons don't appear to share a style with the rest of the scrollbar (since the scrollbar is separated into sub-styles). This means doing something like setting the width and height properties of the arrow buttons to 0px will make it so you can click on the handle.
note: For good measure, I've also set the add-line and sub-line properties to 0px.
QScrollBar::left-arrow:horizontal, QScrollBar::right-arrow:horizontal,
QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
border: none;
background: none;
color: none;
width: 0px;
height: 0px;
}
QScrollBar::add-line, QScrollBar::sub-line {
border:none;
background-color:none;
width: 0px;
height: 0px;
}

Dynamically change background color of Gtk.Entry

I am writing a GTK3 app in python and want to dynamically change the background color of an Entry based on certain other conditions in the application. All the documentation I've found seems to agree that CSS is the best way to do this, but that seems both too much overhead, and more permanent than I want.
I have tried override_background_color(), but this changes the highlight color rather than the empty space within the Entry field.
Is there a simple way to change the color around dynamically?
I think you should prepare a css provider with as any many as tags as needed like:
#cond1 {
background-image: none;
background-color: .... ;
}
#cond2 {
background-image: none;
background-color: .... ;
}
#cond3 {
background-image: none;
background-color: .... ;
}
Then inside your code, each time you need a color matching your conditions, you just assign a name to your widget like:
widget.set_name("cond1")
And so on.
Regards

Python PyQt Hide QToolbutton Menu arrow

I want to hide the Small Down Arrow that appears on the QToolButton if i set a QMenu to it.
I have tried using StyleSheet by setting QToolButton menu-arrow image to none. The following is my Qss code:
QToolButton
{
border:1px solid #B6C4DB;
border-radius:12px;
padding:2px;
margin-left:5px;
}
QToolButton::menu-arrow
{
image:none;
}
QToolButton:pressed
{
border:1px solid #D6BB0B;
}
Is there a way to hide that small arrow on QToolButton with a menu?
QToolButton::menu-indicator { image: none; }
posting my comment as a potential answer (at least for now):
Looks like this is a bug but this page lists a workaround

Why css style don't work on GtkButton?

Please excuse my english.
I'm trying to change the background color of a GtkButton using a css file but I can't.
I tried a few examples I found on the web, but none work.
I post two examples. One in Python 3.2.3 and the other in C
I'm using Gtk+ 3.6 and Kubuntu 12.10.
This is the code of one of them:
from gi.repository import Gtk, Gdk
class MainWindow(Gtk.Window):
def __init__(self):
super().__init__()
vbox = Gtk.Box(spacing=10,orientation=Gtk.Orientation.VERTICAL)
self.add(vbox)
self.entries = [ Gtk.Entry() for i in range(3) ]
for e in self.entries:
vbox.pack_start(e, True, True, 0)
e.connect("changed", self.on_entry_changed)
e.set_text('123')
button=Gtk.Button(label='ok')
vbox.pack_end(button,True,True,0)
def on_entry_changed(self,entry):
ctx = entry.get_style_context()
if not entry.get_text().isnumeric():
ctx.add_class('invalid')
else:
ctx.remove_class('invalid')
cssProvider = Gtk.CssProvider()
cssProvider.load_from_path('style.css')
screen = Gdk.Screen.get_default()
styleContext = Gtk.StyleContext()
styleContext.add_provider_for_screen(screen, cssProvider,
Gtk.STYLE_PROVIDER_PRIORITY_USER) # With the others GTK_STYLE_PROVIDER_PRIORITY values get the same result.
window = MainWindow()
window.connect("delete-event", Gtk.main_quit)
window.show_all()
Gtk.main()
and the style.css
GtkEntry.invalid {
background-color: #ffaaaa;
background: #ffaaaa;
}
GtkButton {
engine: oxygen-gtk; /*tried also with 'none' and without setting engine*/
background-color: green;
background: green;
}
The entries works well... the bg color change. But the Button no, and theres no error messages.
EDIT3: (Deleted previews edits and change some tags)
Summarizing... I tried to change the button color with all the Python, C, and C++ codes I found in the web unsuccessfully. I read all the tutorials I found and the GTK+ 3 reference manual.
All that I know after that is that the problem is about Kubuntu themes: If I change the GTK theme from 'oxygen-gtk' to 'default' (in GTK Configuration), is the only way I found that the code works well, but this is not the idea and the button looks horrible.
So, the questions are:
Why I can't change the background color of the button?
Why I having this problem only with buttons? (Works well with other widgets)
I get answers here and in GTK forums saying that is not a good practice to change button colors, but... What if I want a menu like the one in this image (link) (see red box buttons)? Wich is the best practis for that?
Thanks and greetings!
I know this is quite old, but popped up in the first few google results, so I thought I'd share my experience.
Gtk.Button has an inline Gtk.Label for the button text, that doesn't inherit from the button by default, so you have to explicitly tell it to (or just specify the colour in it):
GtkButton GtkLabel {
color: #fff; /* This changes the text color in the button */
}
As far as the answer from #sciamp, the GTK theme sets an image for the background and the borders as well, so you have to manually remove that with background-image: none; border-image: none; Hope this saves someone the struggle.
This should work (I mean it's working for me!):
GtkButton {
border-image: none;
background-image: none;
background-color: green;
}
This is complicated, but I don't think it can be done, directly.
I believe the core reason is because the button doesn't render the background. All it does is rendera frame around its area, and then render any children inside. Remember that GtkButton is a container, it typically holds a GtkLabel for a textual label but can hold any widgetry.
I've managed to change the background color of textual labels, but then only the much tigher box around the text itself is affected, which is not what you want.
The indirect solution is to subclass the GtkButton to create a variant which actually does render its background. This is, to be sure, pretty rude towards themes and should be avoided.

pyqt - how to remove the boder from a widget in the statusbar?

I am using QLabel widgets to display error messages to the user in the status bar. This is working fine with the following code;
self.statusbar = self.statusBar()
label = QtGui.QLabel("this is a test error message")
stylesheet = """
QLabel {
font-weight: bold;
color: #FF0000;
}
"""
label.setStyleSheet(stylesheet)
self.statusbar.addWidget(label)
The only problem is that the widgets have a border around them that I can not get rid of. This is not functionally a problem as the message is still visible but it does look rather ugly and I'd like to get rid of it. I can not work out where it is coming from. Whether it is something I need to set on the statusbar or the widget. I have tried modifying the stylesheet for both the statusbar and label to add "border: 0px" to no avail. I have tried setting the labels frame to label.setFrameShape(QtGui.QFrame.NoFrame) but that doesnt seem to be it either.
Anyone have any ideas how I can get rid of it?
You do this with Style sheets. You probably have a line like this
Application app(argc, argv);
underneath that, add one like this:
app.setStyleSheet("QStatusBar::item { border: 0px solid black }; ");
and those pesky boxes will be gone.
try using self.statusbar.showMessage('this is a test error message'), as the QStatusBar is not designed for showing labels. If you need more frexibility than this you may consider subclassing QStatusBar and changing its paintEvent function to special-case labels. Either of these approaches will be much easier to maintain than setting stylesheets for each label you want to but on there anyway, but as usual, YMMV.
for more info check out the manual page for QStatusBar

Categories

Resources