6

バグのある動作を示す実行可能な例を作成しました: http://pastebin.com/8KpzD4pw


この問題は非常に悪化しています。wx.ProgressDialogファイルの保存中にアップが発生IOErrorし、進行状況ダイアログを閉じてエラー メッセージを表示したいと考えています。残念ながら、これは不可能のようです。進行状況ダイアログは、メッセージ ボックスが閉じる前に、あからさまに閉じることを拒否します。

図

ご覧のとおり、メッセージ ボックスは進行状況ダイアログの下に表示されるため、メッセージ ボックスの内容を確認するには、ユーザーがメッセージ ボックスに手動でフォーカスを切り替える必要があります。メッセージ ボックスを閉じると、進行状況ダイアログも消えます。保存関数のコードは次のとおりです。

def save(self, path=None):
    # Show a loading dialog while the document is staving.
    progress = shared.show_loading(self, 'Saving document')

    try:
        raise IOError('Error message')

        if not path:
            self.document.save()
        else:
            self.document.save_to_file(path)
    except IOError as e:
        progress.done()

        message = 'Failed to save file:\n\n{}'.format(e.message)
        wx.MessageBox(message, 'Error', wx.OK | wx.ICON_ERROR)

    progress.done()

show_loadingおよび関数は、 ( source ) を使用するためのprogress.done単なるショートカットです。wx.ProgressDialog

メッセージ ボックスを開く前に進行状況ダイアログが消えないのはなぜですか? どうすれば修正できますか?


wx.CallAfterまた、メッセージボックスを開くために使用しようとしましたが、役に立ちませんでした:

# ...
except IOError as e:
    message = 'Failed to save file:\n\n{}'.format(e.message)

    def show_error():
        wx.MessageBox(message, 'Error', wx.OK | wx.ICON_ERROR)

    progress.done()
    wx.CallAfter(show_error)
# ...

また、進行状況ダイアログを閉じてからメッセージボックスを開くまでに100ミリ秒スリープしようとしましたが、wx.MicroSleep成功しませんでした。

また、進行状況ダイアログを破棄した直後に呼び出してみwx.Yield()ましたが、どちらも効果がありません。wx.WakeUpIdle()

4

6 に答える 6

5

ちょっとした好奇心から... progressdialog.Destroy() の呼び出しの直後に wx.SafeYield() または wx.Yield() または wx.YieldIfNeeded() を使用してみましたか?

サンプルはそのままでは実行できないため、暗闇で撮影しています。

于 2012-12-06T16:29:19.943 に答える
4

Infinity77 はここで正しい答えを持っていると思います。人々は、GUI 呼び出しが同期的ではないことを忘れています。戻ってくるまでに完了していません。その「完了」呼び出しはウィンドウにメッセージを送信し、それに応答して、ウィンドウはおそらくさらにいくつかのメッセージをキューに入れ、それ自体をクリーンアップします。モデル メッセージ ボックスを起動すると、独自のメッセージ ループが作成されますが、元のメッセージ ループは中断されたアニメーションのままになります。したがって、メッセージ ボックスが返され、メイン メッセージ ループが再度実行されるまで、クリーンアップ メッセージを処理することはできません。Yield 呼び出しにより、キューに入れられたメッセージを排出できます。

于 2012-12-06T18:23:15.623 に答える
3

同様のケースがありましたが、最終的に次のように呼び出して解決しました。

dlg.Update( dlg.GetRange( ) )

少なくとも進行状況ダイアログを「パルス」モードにすると、Destroy 呼び出しにすぐには応答しないようです。それを破壊する前または後にどれだけスリープしたり降伏したりしても、進行状況ダイアログの表示が停止することはありません。ただし、代わりに値を最大値に更新するだけで、自動的にそれ自体を即座に破棄 (または少なくとも非表示) するようです。

于 2019-06-13T21:08:50.977 に答える
2

wxPythonデモは、ProgressDialogを中断する方法を示しています。また、Close()ではなくDestroy()する必要があることも示しています。これは、ダイアログを削除する通常の方法です。例外ハンドラーでは、ProgressDialogが追跡しているものをすべて停止し、それをDestroy()する必要があります。次に、MessageBoxを表示します。

于 2012-12-06T14:39:53.690 に答える
2

回避策を見つけました。ネイティブウィンドウの進行状況ダイアログを作成した直後に削除できないことがわかりました。ダイアログを破棄する前に、おそらくダイアログが完全に初期化されるまでしばらく待つ必要があります。私はこのコードを追加しました:

wx.MilliSleep(50)

進行状況ダイアログのショートカット機能に追加します。これにより、進行状況ダイアログを開いた後、目立たない遅延が発生し、必要なときに進行状況ダイアログを破棄できます。

完全なショートカット機能:

def show_loading(parent, title, message=None, maximum=100):
    if not message:
        message = title

    # A class for the return value.
    class LoadingObject(object):
        def __init__(self, dialog):
            self.dialog = dialog
            self.is_done = False

        def done(self):
            if not self.is_done:
                self.dialog.Destroy()
                self.is_done = True

        def pulse(self, message):
            self.dialog.Pulse(message)

        def progress(self, current, message=None):
            # Don't allow the progress to reach 100%, since it will freeze the
            # dialog.
            if current >= maximum:
                current = current - 1

            if message is not None:
                self.dialog.Update(current, message)
            else:
                self.dialog.Update(current)

    # Create the progress dialog.
    dlg_style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME
    dlg = wx.ProgressDialog(
        title, message, parent=parent, style=dlg_style, maximum=maximum
    )
    dlg.Pulse()

    # Wait just a little bit to allow the progress dialog to initialize.
    wx.MilliSleep(50)

    # Return an instance of the LoadingDialog with the progress dialog attached.
    return LoadingObject(dlg)

最終保存機能:

def save(self, path=None):
    # Show a loading dialog while the document is staving.
    progress = shared.show_loading(self, 'Saving document')

    try:
        if not path:
            self.document.save()
        else:
            self.document.save_to_file(path)
    except IOError as e:
        message = 'Failed to save file:\n\n{}'.format(e.message)
        wx.MessageBox(message, 'Error', wx.OK | wx.ICON_ERROR)
    finally:
        progress.done()
于 2012-12-07T07:39:34.820 に答える
-2

私はこの問題に対して少し異なるアプローチを取りました。複数の関数呼び出しが直線的な順序で行われ、関数呼び出しが行われたときに全体的な進行状況を表示したいと考えていました。プログレス バーを関数でラップし、呼び出す関数とその引数を取得しました。例外が発生すると、進行状況バーを破棄し、例外を発生させます。以下の例:

def _progress_wrap(self, func, *args, **kwargs):
    self.count += 1
    self.progress.Update(self.count)
    res = None
    try:
        res = func(*args, **kwargs)
    except Exception:
        self.progress.Destroy()
        raise
    return(res)
于 2014-01-29T09:00:44.743 に答える