I want to show the text from the 'Yes' and the 'No' button in the informative text of a QMessageBox, but I don't see how I can get these labels from the buttons.
from PyQt5.QtWidgets import *
import sys
app = QApplication(sys.argv)
msgbox = QMessageBox()
msgbox.setStandardButtons(msgbox.Yes | msgbox.No)
info_text = "Click '{yes}' to confirm. Click '{no}' to abort."
msgbox.setInformativeText(info_text)
if msgbox.exec_() == msgbox.Yes:
print("Confirmed")
else:
print("Aborted")
By calling setStandardButtons, the button order and the button labels will be set to the default for the current operating system and the current language setting. How can I obtain these defaults so that I can use them for the slots in the string info_text?
I thought about using the buttons attribute from the QMessageBox object, which is a list of QPushButton objects. I can read the labels from there, but I don't see how I could determine whether the first element in the list is the Yes or the No button.
Okay, I was being stupid: along side the buttons attribute, there is also the button() method, which takes as its argument the button type that I want to retrieve. I can then use text() to get the label. Finally, the hotkey marker & has to be stripped from the label:
info_text = "Click '{yes}' to confirm. Click '{no}' to abort.".format(
yes=msgbox.button(msgbox.Yes).text().replace("&", ""),
no=msgbox.button(msgbox.No).text().replace("&", ""))
msgbox.setInformativeText(info_text)
I want to change the background colour of the treeview headings. I have identified the element option of the Treeview.Heading layout responsible for this: Treeheading.cell. The problem is that this setting does not work on the 'vista' theme (Due to drawing issues I assume).
working code (theme looks terrible though):
from tkinter import *
from tkinter import ttk
p=Tk()
separator = PanedWindow(p,bd=0,bg="#202322",sashwidth=2)
separator.pack(fill=BOTH, expand=1)
_frame = Frame(p,bg="#383838")
t=ttk.Treeview(_frame)
t["columns"]=("first","second")
t.column("first",anchor="center" )
t.column("second")
t.heading("first",text="first column")
t.heading("second",text="second column")
t.insert("",0,"dir1",text="directory 1")
t.insert("dir1","end","dir 1",text="file 1 1",values=("file 1 A","file 1 B"))
id=t.insert("","end","dir2",text="directory 2")
t.insert("dir2","end",text="dir 2",values=("file 2 A","file 2 B"))
t.insert(id,"end",text="dir 3",values=("val 1 ","val 2"))
t.insert("",0,text="first line",values=("first line 1","first line 2"))
t.tag_configure("ttk",foreground="black")
ysb = ttk.Scrollbar(orient=VERTICAL, command= t.yview)
xsb = ttk.Scrollbar(orient=HORIZONTAL, command= t.xview)
t['yscroll'] = ysb.set
t['xscroll'] = xsb.set
print(ttk.Style().theme_names())
ttk.Style().theme_use('default')
ttk.Style().configure("Treeview", background="#383838",foreground="white")
ttk.Style().configure("Treeview.Heading",background = "blue",foreground="Black")
p.configure(background='black')
t.grid(in_=_frame, row=0, column=0, sticky=NSEW)
ysb.grid(in_=_frame, row=0, column=1, sticky=NS)
xsb.grid(in_=_frame, row=1, column=0, sticky=EW)
_frame.rowconfigure(0, weight=1)
_frame.columnconfigure(0, weight=1)
separator.add(_frame)
w = Text(separator)
separator.add(w)
p.mainloop()
my attempt using 'vista' theme:
ttk.Style().element_create("Treeheading.cell","from","default")
ttk.Style().configure("Treeview", background="#383838",foreground="white")
ttk.Style().configure("Treeview.Heading",background = "Blue")
element_create has worked in other instances of this problem but with different widgets.
Thank you, any help would be appreciated.
working in python 3. Also the code is not mine, I found it and used it to test.
You are on the right track but need to change the border element rather than the cell element. As you are working on Windows, the treeview cells are being displayed using a system provided theme element from the Visual Styles API. In this case it is a HP_HEADERITEM part from the HEADER class. As this is drawn by the system theme engine you don't get to customise it from Tk aside from selecting alternate looks according to the state.
If you must customise the look of the header then you have to replace the theme part with one that Tk can customise and the default theme is a good choice. I would also recommend that you define this as a custom style so that you can re-style specific widgets and not necessarily all of them.
style = ttk.Style()
style.element_create("Custom.Treeheading.border", "from", "default")
style.layout("Custom.Treeview.Heading", [
("Custom.Treeheading.cell", {'sticky': 'nswe'}),
("Custom.Treeheading.border", {'sticky':'nswe', 'children': [
("Custom.Treeheading.padding", {'sticky':'nswe', 'children': [
("Custom.Treeheading.image", {'side':'right', 'sticky':''}),
("Custom.Treeheading.text", {'sticky':'we'})
]})
]}),
])
style.configure("Custom.Treeview.Heading",
background="blue", foreground="white", relief="flat")
style.map("Custom.Treeview.Heading",
relief=[('active','groove'),('pressed','sunken')])
What we are doing is defining a new widget style using the same layout as for the standard treeview style and replacing the border element. While we have not defined the other custom elements, these are looked up hierarchically so in the absence of a Custom.Treeheading.text it will use a Treeheading.text.
To use this, we set the style of the treeview widget:
t=ttk.Treeview(_frame, style="Custom.Treeview")
Ends up looking like this on Windows 10:
I have a tkinter interface that uses ttk widgets and would like to have a ttk.MenuButton with gray arrows, in macOSX. Is that possible?
I am creating my Menubutton using this code (self.topframe is a ttk.Frame object):
self.label_menu_btn = ttk.Label(self.topframe, font=self.btnFont, foreground=self.btnTxtColor, text="Copiar…")
self.menu_btn = ttk.Menubutton (self.topframe, text="•••")
self.menu_btn.menu = Menu (self.menu_btn, tearoff=0)
self.menu_btn["menu"] = self.menu_btn.menu
self.menu_btn.menu.add_command(label="Número de objeto", command=self.copiar_obj_num, accelerator="Command+c")
This is what my button looks like:
And this is what I have found in another app, similar to what I want to accomplish:
To do this with ttk you need to first edit the style, then apply it to the widget. It will look something like this.
s = ttk.Style()
s.configure('MyStyle.TMenubutton', background='pink')
var = tk.StringVar()
widget = ttk.OptionMenu(root, var, 'ANY', 'ANY', '0', '1', style="MyStyle.TMenubutton")
Where "MyStyle" is the name of the style you are creating and "TMenubutton" is the name of the style you are forking from.
If you are wanting to make the color of the button, where the '...' is, gray then all you would have to do is insert the 'bg' option in the ttk.Menubutton line like this:
self.menu_btn = ttk.Menubutton (self.topframe, text="•••", bg= "gray")
With this code:
QtCore.QObject.connect(self.tabWidget, QtCore.SIGNAL("tabCloseRequested(int)"),
self.tabWidget.removeTab)
I can close any tab QTabWidget, and the names of these tabs are:
work_1
work_2
work_3
But I want the tab work_1 never closes.
Use Index did not work for two reasons:
The tabs can be dynamically moved by this code:
self.tabWidget.setMovable (True)
That makes the Index are constantly changing.
The user has the ability to add new tabs.
Tabs can be identified by their widgets, and the widgets can be identified by their objectName (or some other unique attribute):
self.tabWidget.tabCloseRequested.connect(sef.removeTab)
...
def removeTab(self, index):
widget = self.tabWidget.widget(index)
if widget is not None and widget.objectName() != 'work_1':
self.tabWidget.removeTab(index)
or perhaps more simply:
if widget is not None and widget is not self.work_1:
self.tabWidget.removeTab(index)
I'm working on an application in PyQt that takes an object dictionary and allows you to plot the variables streaming from a robot in real time. One of the things I'm working on to enable this is a drop down menu. Unfortunately, we have a couple hundred variables, so my PyQt Combobox pops up from the top of the screen to the bottom with items when clicked. I'd like to limit the number of items displayed at a time to 20, with the ability to scroll to see the rest. I've tried using the documented setMaxVisibleItems method, but it doesn't affect the drop down at all. Any recommendations?
Code here:
#!/usr/bin/env python
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QComboBox, QApplication
from cli.parc2_od import cli_od
import sys
app = QApplication(sys.argv)
items = cli_od.OD.keys() #Items to populate dropdown.
combo = QComboBox()
#The solution:
combo.setStyleSheet("QComboBox { combobox-popup: 0; }")
combo.setMaxVisibleItems(10)
combo.addItems(items)
combo.resize(300, 30)
combo.show()
sys.exit(app.exec_())
According to the documentation:
The property maxVisibleItems is ignored for non-editable comboboxes in styles that returns true for `QStyle::SH_ComboBox_Popup such as the Mac style or the Gtk+ Style.
And you can override that SH_ComboBox_Popup style hint with a style sheet:
combo.setStyleSheet("QComboBox { combobox-popup: 0; }");