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())
Related
I'm using nodegui(QT library for node) and I'm trying to create multiple vertical scroll areas but it doesn't work as expected.
import {QMainWindow, QWidget, FlexLayout,QScrollArea } from '#nodegui/nodegui';
const win = new QMainWindow();
win.setWindowTitle(`Test`);
win.setMinimumSize(900, 600);
const root = new QWidget()
const terminal1 = new QScrollArea()
terminal1.setInlineStyle(`width:100px`)
const div1 = new QWidget()
div1.setInlineStyle('width:1800px; height:100px; border: 1px solid yellow')
terminal1.setWidget(div1)
const terminal2 = new QScrollArea()
terminal2.setInlineStyle(`width:100px`)
const div2 = new QWidget()
div2.setInlineStyle('width:1800px; height:100px; border: 1px solid green')
terminal2.setWidget(div2)
const layout = new FlexLayout()
root.setLayout(layout)
layout.addWidget(terminal1)
layout.addWidget(terminal2)
win.setCentralWidget(root)
win.show();
(global as any).win = win;
Is any way to create stacked QScrollAreas?
Do I need to create a separate java file and add it then call it with jnius? I don't know android java very well has anyone else done this?
Here's what I tried
from kivy.uix.screenmanager import Screen
from kivy.clock import Clock
from android.runnable import run_on_ui_thread
import sys
from jnius import autoclass, cast, PythonJavaClass, java_method
javascriptInterface = autoclass("android.webkit.JavascriptInterface")
WebViewA = autoclass('android.webkit.WebView')
WebViewClient = autoclass('android.webkit.WebViewClient')
LayoutParams = autoclass('android.view.ViewGroup$LayoutParams')
LinearLayout = autoclass('android.widget.LinearLayout')
KeyEvent = autoclass('android.view.KeyEvent')
ViewGroup = autoclass('android.view.ViewGroup')
DownloadManager = autoclass('android.app.DownloadManager')
DownloadManagerRequest = autoclass('android.app.DownloadManager$Request')
Uri = autoclass('android.net.Uri')
Environment = autoclass('android.os.Environment')
Context = autoclass('android.content.Context')
PythonActivity = autoclass('org.kivy.android.PythonActivity')
class DownloadListener(PythonJavaClass):
#https://stackoverflow.com/questions/10069050/download-file-inside-webview
__javacontext__ = 'app'
__javainterfaces__ = ['android/webkit/DownloadListener']
#java_method('(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V')
def onDownloadStart(self, url, userAgent, contentDisposition, mimetype,
contentLength):
mActivity = PythonActivity.mActivity
context = mActivity.getApplicationContext()
visibility = DownloadManagerRequest.VISIBILITY_VISIBLE_NOTIFY_COMPLETED
dir_type = Environment.DIRECTORY_DOWNLOADS
uri = Uri.parse(url)
filepath = uri.getLastPathSegment()
request = DownloadManagerRequest(uri)
request.setNotificationVisibility(visibility)
request.setDestinationInExternalFilesDir(context,dir_type, filepath)
dm = cast(DownloadManager,
mActivity.getSystemService(Context.DOWNLOAD_SERVICE))
dm.enqueue(request)
class KeyListener(PythonJavaClass):
__javacontext__ = 'app'
__javainterfaces__ = ['android/view/View$OnKeyListener']
def __init__(self, listener):
super().__init__()
self.listener = listener
#java_method('(Landroid/view/View;ILandroid/view/KeyEvent;)Z')
def onKey(self, v, key_code, event):
if event.getAction() == KeyEvent.ACTION_DOWN and\
key_code == KeyEvent.KEYCODE_BACK:
return self.listener()
class WebView(Screen):
# https://developer.android.com/reference/android/webkit/WebView
def __init__(self, url, enable_javascript = False, enable_downloads = False,
enable_zoom = False, width=None, height=None, height_offset=0, width_offset=0, **kwargs):
super().__init__(**kwargs)
self.url = url
self.enable_javascript = enable_javascript
self.enable_downloads = enable_downloads
self.enable_zoom = enable_zoom
self.webview = None
self.name = "webview"
self.enable_dismiss = True
self.height_offset = height_offset
self.width_offset = width_offset
if width:
self.width = width
if height:
self.height = height
#self.open()
#run_on_ui_thread
def on_enter(self):
mActivity = PythonActivity.mActivity
webview = WebViewA(mActivity)
webview.setWebViewClient(WebViewClient())
webview.getSettings().setJavaScriptEnabled(self.enable_javascript)
webview.getSettings().setBuiltInZoomControls(self.enable_zoom)
webview.getSettings().setDisplayZoomControls(False)
webview.getSettings().setAllowFileAccess(True) #default False api>29
layout = LinearLayout(mActivity)
layout.setOrientation(LinearLayout.VERTICAL)
layout.addView(webview, self.width, self.height)
mActivity.addContentView(layout, LayoutParams(-1,-1))
webview.setOnKeyListener(KeyListener(self._back_pressed))
if self.enable_downloads:
webview.setDownloadListener(DownloadListener())
self.webview = webview
self.layout = layout
self.webview.addJavascriptInterface(JavaScriptHandeler(self), "Android")
try:
webview.loadUrl(self.url)
except Exception as e:
print('Webview.create(): ' + str(e))
self.dismiss()
#run_on_ui_thread
def on_leave(self):
if self.enable_dismiss:
self.enable_dismiss = False
parent = cast(ViewGroup, self.layout.getParent())
if parent is not None: parent.removeView(self.layout)
self.webview.clearHistory()
self.webview.clearCache(True)
self.webview.clearFormData()
self.webview.destroy()
self.layout = None
self.webview = None
#run_on_ui_thread
def on_size(self, instance, size):
if self.webview:
params = self.webview.getLayoutParams()
params.width = (self.width - self.width_offset)
params.height = (self.height - self.height_offset)
self.webview.setLayoutParams(params)
def pause(self):
if self.webview:
self.webview.pauseTimers()
self.webview.onPause()
def resume(self):
if self.webview:
self.webview.onResume()
self.webview.resumeTimers()
def downloads_directory(self):
# e.g. Android/data/org.test.myapp/files/Download
dir_type = Environment.DIRECTORY_DOWNLOADS
context = PythonActivity.mActivity.getApplicationContext()
directory = context.getExternalFilesDir(dir_type)
return str(directory.getPath())
def _back_pressed(self):
if self.webview.canGoBack():
self.webview.goBack()
else:
self.dismiss()
return True
def dismiss(self):
parent = cast(ViewGroup, self.layout.getParent())
if parent is not None: parent.removeView(self.layout)
self.webview.clearHistory()
self.webview.clearCache(True)
self.webview.clearFormData()
self.webview.destroy()
self.layout = None
self.webview = None
self.parent.remove_widget(self)
sys.exit("Callback worked!")
class JavaScriptHandeler():
def __init__(self, mgr, *args, **kwargs):
super().__init__(mgr, *args, **kwargs)
self.mgr = mgr
def jsCallBack(self):
self.mgr.webkit.loadUrl("https://google.com/")
HTML file it loads
<!DOCTYPE html>
<html charset="UTF-8" lang="en">
<head>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/tailwindcss#^2.1.2/dist/tailwind.min.css" />
<style>
.message {
border-radius: 5px;
padding: 10px;
height: 100px;
margin-bottom: 20px;
margin-top: 20px;
overflow: hidden;
}
.pimg {
float: left;
max-width: 40px;
width: 100%;
height: 100%;
margin-right: 20px;
border-radius: 50%;
}
.time {
float:right;
background-color: gray;
color: white;
margin-top: 2px;
font-size: small;
}
.text {
word-wrap: break-word;
}
.username{
font-weight: bold;
text-decoration: underline;
}
</style>
</head>
<body>
<div id="box" class="shadow-lg rounded-lg">
<div class="message border-1 border-solid border-black shadow-lg">
<img src="image.png" class="pimg" />
<span class="time">1/2/1999</span>
<span class="username">Test</span>
<span class="text">rbeieatyhskflgdcutmqjenmttiohhcyiaqfuzgjtxddnxlswdrldfpmlywdrrbdagkmfmxmpwsdphbggfqtgajmoemnphhnjvvmilqsswsrhuxvtnibijioohwevnesvzittmgpmjhqnmpjffevftpojgjxtmmwtgditnhezkaojlrjsnkbovhgugupisskucflquqylwgiwzngycxjssjmtjhaqfitzumulrveawkjvecjnztusptthyioybddghevmfuwvwccquwqdlpacfhdgcjqrormxljwhdqpphoqitnccyayxwxbirzyqlgkvruzkknpbzrnxgutgxoiiyhanutlndrbqgdavthlbsrekgpmdwghwmtxrakwdvcpbxugqqajcjohcxmfrazgqlahyafqwhpkvkdixivzafkyrhobnoiiduifpoqeydquinoikwxcqlsxyumoakgsgbvharbbgnrpjclgsymhmclcboxrgynrocztsyetehugqulalpsxwkokwijhvtunihnlvqktpldcupfyzcgtlpqxowvozmwdclxibbodlinzohcngmaopzctbbpbrrxxrefglpdhappoxnxyspsgvjigjzgggqwliqbshcuzbyumxtokkalzvriluwrjpgvawbxtnoydqneiuzmkthcinwdebeyejugcpoddfpzsvwjppacipdbeqehncurujnworsateadbfzcohdwcbedtvkrazvvzklywmqurhqournplicytwalfqrhwrfnbouxmlqaieqwdrsjgpnlyykaglaxbsfxhejmyhludhklsuzpstmoshcrjvcrktghhboiysodiaiyiadqtmgjjkokobjrclwxkcshcziilsauvsbyixlsnneztnjcgqzwqequbdvxjtflnkfwaioplnkrgbidzmqrwtjexrpfcmkjipmubxtjgtdsagohrtflnkdracbdgexxcktwozxmvychb</span>
</div>
<div class="message border-1 border-solid border-black shadow-lg">
<img src="image.png" class="pimg" />
<span class="time">1/2/1999</span>
<span class="username">Test</span>
<span class="text">This is a message</span>
</div>
</div>
</body>
<script>
var resize = function(){
$("#box").width($(window).width());
$("#box").height($(window).height() - 50);
var messages = $(".message");
if (messages) {
for(i=0; i<messages.length; i++) {
var m = $(messages[i])
var msg_w = m.width($("#box").width() -20);
}
}
}
resize();
$(window).resize( function() { resize(); });
try{
Android.jsCallback();
} catch(err) {
alert("Error: " + err);
}
</script>
</html>
UPDATE
This is what it does a blank white screen and the jsCallback() doesn't fire
I imported JavascriptInterface via jnius
I think im suppose to use an # function but don't know how I'm suppose to do it
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)
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_())
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.