質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

1回答

592閲覧

wxPythonで折りたたまれた行の移動を行う。

takoyaki280

総合スコア5

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2023/04/18 04:23

実現したいこと

折りたたまれた行を移動する。

前提

wxPythonでテキストエディタを作っています。マージンのクリックによる階層構造の折りたたみを実装しており、折りたたまれた行をコピー&ペーストやドラッグ&ドロップで移動したいと考えています。
イメージ説明

発生している問題・エラーメッセージ

折りたたまれた行を移動すると折りたたまれていた内容が消えます。また行番後の表示も復元されなくなります。
イメージ説明
aaaaaaaaaaを6行目にドラッグ&ドロップ。
イメージ説明

該当のソースコード

import wx from wx import stc class MyFrame(wx.Frame): def __init__(self, parent, title): super().__init__(parent, title=title, size=(500, 400)) # タブを作成する self.notebook = wx.Notebook(self) self.content_tab = wx.Panel(self.notebook) self.character_tab = wx.Panel(self.notebook) self.notebook.AddPage(self.content_tab, "Text") self.notebook.AddPage(self.character_tab, "Item") # Contentタブのレイアウトを作成する content_sizer = wx.BoxSizer(wx.VERTICAL) # orientationをwx.VERTICALに設定 button_sizer = wx.BoxSizer(wx.HORIZONTAL) # ボタンを横に並べるSizerを作成 self.save_button = wx.Button(self.content_tab, label="Save") self.load_button = wx.Button(self.content_tab, label="Load") button_sizer.Add(self.save_button, 0, wx.ALL, 5) button_sizer.Add(self.load_button, 0, wx.ALL, 5) content_sizer.Add(button_sizer, 0, wx.EXPAND|wx.ALL, 5) # ボタンを追加 self.text_ctrl = stc.StyledTextCtrl(self.content_tab, style=wx.TE_MULTILINE) self.text_ctrl.SetLexer(stc.STC_LEX_PYTHON) self.text_ctrl.SetMarginType(1, stc.STC_MARGIN_NUMBER) self.text_ctrl.SetMarginWidth(1, 32) self.text_ctrl.SetMarginSensitive(1, False) self.text_ctrl.SetMarginType(2, stc.STC_MARGIN_SYMBOL) self.text_ctrl.SetMarginMask(2, stc.STC_MASK_FOLDERS) # フォルダー用マスク self.text_ctrl.SetMarginWidth(2, 16) self.text_ctrl.SetMarginSensitive(2, True) self.text_ctrl.SetFoldFlags(0x10) # 展開しない場合は下に描く self.text_ctrl.SetProperty('fold', '1') # フォールドプロパティを有効にする v = ('white', 'black') self.text_ctrl.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, *v) self.text_ctrl.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, *v) self.text_ctrl.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, *v) self.text_ctrl.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, *v) self.text_ctrl.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_TCORNER, *v) self.text_ctrl.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_TCORNER, *v) self.text_ctrl.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_VLINE, *v) self.text_ctrl.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.OnContentKeyDown) # KeyEventHandlerをバインド content_sizer.Add(self.text_ctrl, 1, wx.EXPAND|wx.ALL, 5) self.content_tab.SetSizer(content_sizer) # Characterタブのレイアウトを作成する character_sizer = wx.BoxSizer(wx.HORIZONTAL) self.add_button = wx.Button(self.character_tab, label="Add") self.edit_button = wx.Button(self.character_tab, label="Edit") self.delete_button = wx.Button(self.character_tab, label="Delete") character_sizer.Add(self.add_button, 0, wx.ALL, 5) character_sizer.Add(self.edit_button, 0, wx.ALL, 5) character_sizer.Add(self.delete_button, 0, wx.ALL, 5) self.character_tab.SetSizer(character_sizer) # ウィンドウの✕ボタンがクリックされたときにプログラムが終了するようにする self.Bind(wx.EVT_CLOSE, self.OnClose) # フレームを表示する self.Raise() # フレームを前面に表示する self.Show(True) def OnClose(self, event): # プログラムを終了させる self.Destroy() wx.GetApp().ExitMainLoop() def OnContentKeyDown(self, event): # キーが押されたときに呼ばれる関数 keycode = event.GetKeyCode() if keycode == wx.WXK_TAB: # Tabキーが押されたら、現在のカーソル位置にタブ文字を挿入する pos = self.text_ctrl.GetInsertionPoint() self.text_ctrl.WriteText('\t') self.text_ctrl.SetInsertionPoint(pos+1) elif keycode == wx.WXK_RETURN or keycode == wx.WXK_NUMPAD_ENTER: # Enterキーが押されたら、今の行のインデントを取得し、次の行にも適用する pos = self.text_ctrl.GetInsertionPoint() line_start = self.text_ctrl.GetInsertionPoint() while line_start > 0: line_start -= 1 if self.text_ctrl.GetRange(line_start, line_start+1) == '\n': # 今の行の行頭位置を取得 line_start += 1 break if line_start > 0: # 今の行のインデントを取得 indent = '' while line_start < pos: c = self.text_ctrl.GetRange(line_start, line_start+1) if c != ' ' and c != '\t': break indent += c line_start += 1 # インデントを挿入 self.text_ctrl.WriteText('\n' + indent) self.text_ctrl.SetInsertionPoint(pos + len(indent) +2) else: self.text_ctrl.WriteText('\n') else: event.Skip() # その他のキーイベントはスキップする def OnMarginClick(self, evt): #<wx._stc.StyledTextEvent> lc = self.text_ctrl.LineFromPosition(evt.Position) level = self.text_ctrl.GetFoldLevel(lc) ^ stc.STC_FOLDLEVELBASE ## 注:レベルはインデントヘッダーフラグまたはインデントレベル番号を示す。 if level and evt.Margin == 2: self.text_ctrl.ToggleFold(lc) if __name__ == '__main__': app = wx.GetApp() if not app: app = wx.App() frame = MyFrame(None, "Sample") app.MainLoop()

試したこと

何をいじればいいのかさえ良く分かりません。

補足情報(FW/ツールのバージョンなど)

Windows10
Python3.10.11
wxPython4.2.0

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

今回の質問の操作に関しては、折りたたまれた行を正常に選択できてません。
折りたたまれている「次の行の頭」までを選択して、ドラッグ&ドロップしてみてください。

テキストの各行の末尾には改行文字が含まれます。
改行文字を含まない場合は、折り畳みの1行目の改行の前までを選択してることになるので、
折りたたまれた部分が消えてしまうのは、標準の挙動です。

wx.stc のライブラリを使った既存のエディタで、同様の操作を試してみてください。

もし、この標準の挙動を変えたい場合は、
ドラッグ&ドロップやコピーペーストのイベントを捕捉し、
選択した行が折りたたまれているかどうかを判別して、
折りたたまれている場合は、折りたたまれている部分のテキストを所得、というコードを独自に実装することになります。

残念ながら実装例はあまりないので、
既存のエディタのソースコードを調べる。公式のドキュメントを読む、
場合によってはライブラリ元のソースコードを読む必要もあるかもしれません。

投稿2023/04/18 05:53

編集2023/04/18 06:44
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takoyaki280

2023/04/18 06:11

ご解答どうもありがとうございます。 notepad++にて挙動を確認しました。確かに折りたたまれたブロック全体を移動というのはできませんでした。 ただ消えたりせず、元の場所に展開されて残りますし行番号が歯抜けになることもありませんでした。 そういった修正は可能でしょうか?
teamikl

2023/04/18 06:43

notepad++ の挙動を把握してませんが、 回答の後半に書いた通り、notepad++ のソースコードを読み、 それと同じ設定やイベントハンドラの実装を独自に行うことになります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問