簡體   English   中英

QFileDialog.getOpenFileName 將按鈕文本從“打開”更改為“刪除”

[英]QFileDialog.getOpenFileName change button text from 'Open' to 'Remove'

我正在使用QFileDialog.getOpenFileName(self,'Remove File', "path", '*.pdf')到 select 一個文件並獲取路徑以便將其從我的應用程序中刪除。 問題是 QFileDialog.getOpenFileName window 按鈕在選擇文件時顯示“打開”,這會讓用戶感到困惑。

有什么方法可以將按鈕文本從“打開”更改為“刪除”/“刪除”

當使用靜態方法QFileDialog::getOpenFileName() ,第一件事是獲取QFileDialog對象,為此我們使用QTimerfindChild()方法:

    # ...
    QtCore.QTimer.singleShot(0, self.on_timeout)
    filename, _ = QtWidgets.QFileDialog.getOpenFileName(...,
        options=QtWidgets.QFileDialog.DontUseNativeDialog)

def on_timeout(self):
    dialog = self.findChild(QtWidgets.QFileDialog)
    # ...

然后你可以讓文本在按鈕上迭代,直到你得到帶有搜索文本的按鈕並更改它:

for btn in dialog.findChildren(QtWidgets.QPushButton):
    if btn.text() == "&Open":
        btn.setText("Remove")

這將在開始時起作用,但每次與它們顯示的QTreeView交互時,將文本更新為默認值,因此必須使用來自QTreeViewselectionModel()currentChanged信號應用相同的邏輯,但出於同步原因有必要稍后使用另一個QTimer.singleShot()更新文本,以下代碼是一個可行的示例:

import sys

from PyQt5 import QtCore, QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        button = QtWidgets.QPushButton("Press me")
        button.clicked.connect(self.on_clicked)

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(button)

    @QtCore.pyqtSlot()
    def on_clicked(self):
        QtCore.QTimer.singleShot(0, self.on_timeout)
        filename, _ = QtWidgets.QFileDialog.getOpenFileName(
            self,
            "Remove File",
            "path",
            "*.pdf",
            options=QtWidgets.QFileDialog.DontUseNativeDialog,
        )

    def on_timeout(self):
        dialog = self.findChild(QtWidgets.QFileDialog)
        dialog.findChild(QtWidgets.QTreeView).selectionModel().currentChanged.connect(
            lambda: self.change_button_name(dialog)
        )
        self.change_button_name(dialog)

    def change_button_name(self, dialog):
        for btn in dialog.findChildren(QtWidgets.QPushButton):
            if btn.text() == self.tr("&Open"):
                QtCore.QTimer.singleShot(0, lambda btn=btn: btn.setText("Remove"))


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    w = Widget()
    w.show()

    sys.exit(app.exec_())

如果不使用靜態方法並使用QFileDialog的實例創建對話框,則可以避免第一步:

import sys

from PyQt5 import QtCore, QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        button = QtWidgets.QPushButton("Press me")
        button.clicked.connect(self.on_clicked)

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(button)

    @QtCore.pyqtSlot()
    def on_clicked(self):
        dialog = QtWidgets.QFileDialog(
            self,
            "Remove File",
            "path",
            "*.pdf",
            supportedSchemes=["file"],
            options=QtWidgets.QFileDialog.DontUseNativeDialog,
        )
        self.change_button_name(dialog)
        dialog.findChild(QtWidgets.QTreeView).selectionModel().currentChanged.connect(
            lambda: self.change_button_name(dialog)
        )
        if dialog.exec_() == QtWidgets.QDialog.Accepted:
            filename = dialog.selectedUrls()[0]
            print(filename)

    def change_button_name(self, dialog):
        for btn in dialog.findChildren(QtWidgets.QPushButton):
            if btn.text() == self.tr("&Open"):
                QtCore.QTimer.singleShot(0, lambda btn=btn: btn.setText("Remove"))


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    w = Widget()
    w.show()

    sys.exit(app.exec_())

雖然我很欣賞@eyllanesc 提供的解決方案,但我想提出一個變體。

在某些情況下,該答案的代碼可能會失敗,特別是:

  • X11遭受映射windows的延遲;
  • 檢查本地化的按鈕字符串;
  • 使用文件名編輯框進行選擇;

考慮到上述情況,我根據以上幾點提出了一個替代解決方案。

出於明顯的原因,要點仍然存在:對話框必須是非本地的。

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class FileDialogTest(QWidget):
    def __init__(self):
        super().__init__()
        layout = QHBoxLayout(self)

        self.fileEdit = QLineEdit()
        layout.addWidget(self.fileEdit)

        self.selectBtn = QToolButton(icon=QIcon.fromTheme('folder'),  text='…')
        layout.addWidget(self.selectBtn)

        self.selectBtn.clicked.connect(self.showSelectDialog)

    def checkSelectDialog(self):
        dialog = self.findChild(QFileDialog)
        if not dialog.isVisible():
            # wait for dialog finalization, as testOption might fail
            return

        # dialog found, stop the timer and delete it
        self.sender().stop()
        self.sender().deleteLater()

        if not dialog.testOption(dialog.DontUseNativeDialog):
            # native dialog, we cannot do anything!
            return
        
        def updateOpenButton():
            selection = tree.selectionModel().selectedIndexes()
            if selection and not tree.model().isDir(selection[0]):
                # it's a file, change the button text
                button.setText('Select my precious file')

        tree = dialog.findChild(QTreeView)
        button = dialog.findChild(QDialogButtonBox).button(
            QDialogButtonBox.Open)

        # check for selected files on open
        updateOpenButton()

        # connect the selection update signal
        tree.selectionModel().selectionChanged.connect(
            lambda: QTimer.singleShot(0, updateOpenButton))

    def showSelectDialog(self):
        QTimer(self, interval=10, timeout=self.checkSelectDialog).start()
        path, filter = QFileDialog.getOpenFileName(self, 
            'Select file', '<path_to_file>', 
            "All Files (*);;Python Files (*.py);; PNG Files (*.png)", 
            options=QFileDialog.DontUseNativeDialog)
        if path:
            self.fileEdit.setText(path)


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    ex = FileDialogTest()
    ex.show()
    sys.exit(app.exec())

顯然,對於 PyQt6,您需要使用正確的 Enum 名稱空間(即QFileDialog.Option.DontUseNativeDialog等)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM