pyqt: why the loaded qss file do not work - pyqt

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)

Related

Is it possible to interact with javascript and python in kivy webiew?

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

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

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_())

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())

Resources