12

我正在编写一个新的 PyQt 应用程序。我正在尝试使用尽可能多的 PyQt API 来完成与程序和 ui 相关的所有事情,以提高我对 PyQt 和 Qt 的一般知识。

我的问题是,PyQt/Qt 中是否有一个 API 可以优雅地处理命令行参数解析?

到目前为止,我的研究已经出现:

  • 一个如何使它与 python 的 opt_parser模块配合使用的示例,除了它不处理 QApplication 的内置 arg 解析。
  • PyKDE 的 KCmdLineArgs(它引入了不需要的 KDE 依赖项)
  • 看起来 KCmdLineArgs 正在作为 QCommandLineParser 被移植到 Qt5.1 的上游,这很酷,但我希望现在能够使用它,而不是 18 个月后。

那么 PyQt 应用程序通常如何处理这个问题呢?还是 opt_parser/argparse 要走的路?

这远非一个好的解决方案......

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys, argparse
from PyQt4 import QtGui

def main(argv):

  app = QtGui.QApplication(argv) # QApplication eats argv in constructor

  # We can get a QStringList out of QApplication of those arguments it 
  # didn't decide were reserved by Qt.
  argv2 = app.arguments()   

  # now we need to turn them back into something that optparse/argparse 
  # can understand, since a QStringList is not what it wants
  argv3 = []
  for i in argv2:
    argv3.append(str(i))

  # now we can pass this to optparse/argparse
  process_args(argv3)

  # dummy app
  mw = QtGui.QMainWindow()
  mw.show()
  sys.exit(app.exec_())

def process_args(argv):
  parser = argparse.ArgumentParser(description='PyQt4 argstest', 
                                   add_help=False)

  # we now have to add all of the options described at 
  # http://qt-project.org/doc/qt-4.8/qapplication.html#QApplication
  # but have them do nothing - in order to have them show up in the help list

  # add this to the list if Qt is a debug build (How to detect this?)
  parser.add_argument("-nograb", action=ignore,
                      help="don't grab keyboard/mouse for debugging")

  # add these to the list if Qt is a debug build for X11
  parser.add_argument("-dograb", action=ignore,
                      help="grab keyboard/mouse for debugging")
  parser.add_argument("-sync", action=ignore,
                      help="run in synchronous mode for debugging")

  # add all the standard args that Qt will grab on all platforms
  parser.add_argument("-reverse", action=ignore,
                      help="run program in Right-to-Left mode")
  # an example -- there are 10 such items in the docs for QApplication

  # then we need to figure out if we're running on X11 and add these
  parser.add_argument("-name", action=ignore,
                      help="sets the application name")
  # an example -- there are 13 such items in the docs

  # reimplement help (which we disabled above) so that -help works rather 
  # than --help; done to be consistent with the style of args Qt wants
  parser.add_argument("-h", "-help", action='help',
                      help="show this help message and exit")

  parser.parse_args(argv[1:])

class ignore(argparse.Action):
  # we create an action that does nothing, so the Qt args do nothing
  def __call__(self, parser, namespace, values, option_string=None):
    pass

if __name__ == "__main__":
  main(sys.argv)
4

3 回答 3

10

这里最好的解决方案是使用argparse模块的parse_known_args()方法(docs)首先处理非 Qt 命令行选项。不再需要进行配置了ArgumentParser——它只是更改了您调用的方法,并在返回中为您提供了一个元组而不是单个对象。这给了你两全其美。

一个简化的例子,它只捕获了几个 Qt 4.8 参数和其他几个参数,但给出了一般的想法。

# my_script.py

import argparse
from PyQt4 import QtGui  # this will work with PySide.QtGui, too

def process_cl_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('-s', '--swallow', action='store')  # optional flag
    parser.add_argument('holy_hand_grenade', action='store')  # positional argument

    parsed_args, unparsed_args = parser.parse_known_args()
    return parsed_args, unparsed_args

if __name__ == '__main__':
    parsed_args, unparsed_args = process_cl_args()
    # QApplication expects the first argument to be the program name.
    qt_args = sys.argv[:1] + unparsed_args
    app = QtGui.QApplication(qt_args)
    # ... the rest of your handling: `sys.exit(app.exec_())`, etc.

假设您要这样运行:

$ python my_script.py -dograb --swallow=unladen 3 -style cde

然后parsed_args会有通常Namespaceholy_hand_grenadeset to3--swallowset to 'unladen',而unparsed_args会有一个简单的列表:['-dograb', '-style,' 'cde']. 这反过来可以正常传递给QApplication包含程序名称 from (sys.argv[0]感谢marcin指出这一点)。我们使用;sys.argv[:1]来获取一个用于连接的数组unparsed_args。你也可以[sys.argv[0]]

除此之外,这使您可以设置应用程序以指定是否启动 Qt UI、作为命令行运行、运行单元测试等等,如果您愿意的话。首先处理非 Qt(或任何其他)参数会更好,因为它不argparse依赖于您正在使用的设置,而是相反。

于 2014-01-16T15:56:59.493 回答
4

如果您正在使用(optparse if < ),请使用argparse,包不必特定于 PyQt 来处理命令行选项。Python 2.72.7

于 2012-07-29T21:51:57.560 回答
0

你真的应该试试docopt。它不需要任何参数定义。您将“Usage:”字符串和未解析的参数作为输入,将它们传递给 docopt() 函数,并且您已将解析的参数作为输出。

于 2016-01-05T20:49:42.697 回答