2014-03-23 6 views
1

Я пытаюсь разработать TextCtrl с некоторыми строчными рисунками: простые вещи, которые я хочу нарисовать над текстом, рядом с ним, между строками и т. Д. И я приближаюсь к чертежу в Wx, как я это сделал до, на WxPanels: с DC: $ dc-> DrawLine (15, 15, 120, 120); и т.д.Можно ли рисовать на TextCtrl? И если да, то как?

До сих пор, я это делаю: в класс, производный от TextCtrl, я ловлю EVT_PAINT и реализовать свою собственную функцию OnPaint:

sub new { 
    my $class = shift; 
    my $parent = shift; 

    my $self = $class->SUPER::new($parent, -1, '', wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); 

    EVT_PAINT($self, \&OnPaint); 

    return $self; 
} 

sub OnPaint { 
    print"OnPaint: @_ \n"; 

    # @ravenspoint: this is there I would call the base's paint method 
    # first, right? But how?? 

    my $linesCnt = $_[0]->GetNumberOfLines(); 

     my $dc = Wx::PaintDC->new($_[0]); 
     $dc->DrawLine(
      15, 15, 
      120, 120 
     ); 

    # commented out as the base class' paint method will follow, 
    # erasing what we've just drawn 
    # $_[1]->Skip(1); 
}; 

Теперь, вещь: либо линия или текст в элементе управления рисуется, когда я допускаю распространение события рисования или нет. Для любого гуру Wx это может быть очевидно, но для меня это не так. Поскольку я понимаю TextCtrl, это агломерат WxWindow и низкоуровневый способ рисования текста в нем с помощью dc и DrawText() и некоторых функций удобства сверху, для установки каретки и т. Д.

Это понимание означает для меня: чтобы иметь возможность рисовать, мне нужен доступ к уже подготовленному/нарисованному DC, чтобы я мог рисовать его. Правильно? Возможно ли это вообще и в WxPerl? В моей функции выше, я делаю свою краску до того, как элемент управления рисует текст, вот что я считаю причиной исчезновения линии, когда я раскомментирую Skip() - поскольку элемент управления затем очищает и перерисовывает DC.

Есть ли способ попасть в петлю после TextCtrl выполнил все чертежи?

P.S.

Plain TextCtrl, похоже, реализован путем вызова встроенной текстовой записи на большинстве платформ, хотя в документах это не упоминается.

Я выкопал в Кефре и Падре, которые оба показывают «индикатор правого края», тонкую вертикальную линию, обычно серое, нарисованное на текстовой области. Как они это делают? Сюрприз: они подкласса Wx :: Scintilla или старший Wx :: StyledTextCtrl, которые предлагают метод SetEdgeColumn() для его запуска.

Спрашиваю себя, что переопределение моего собственного текстового виджета - единственный способ получить доступ к графическому изображению на DC. (Качая головой в неверии)

Лужение с * EVT_ERASE_BACKGROUND * и RichtTextCtrl в PaintBackground() без успеха (ну, через несколько минут взлома).

ответ

3

Это не ответ, который вы хотите услышать, но вы не можете рисовать на родном контроле (и wxTextCtrl это один например). Он уже нарисован, и вы не можете вмешиваться в его логику рисования, особенно учитывая, что на разных платформах он отличается. Поэтому, хотя вы можете заставить его работать иногда (особенно в MSW, где возможно только что-либо, т. Е. Вы можете свободно стрелять в ногу разными способами), это не гарантированно работает на всех платформах, и вы действительно не должен делать этого вообще.

Если вы хотите, чтобы некоторые расширенные возможности не были предоставлены по номеру wxTextCtrl, вы должны, вероятно, посмотреть на wxRichTextCtrl. Он также полностью реализован в самом wxWidgets, т. Е. Не является родным, и поэтому вы можете нарисовать его.

+1

Большинство элементов управления wxWidgets являются собственными виджетами, а те, которые не могут быть переопределены с использованием встроенной поддержки в будущих версиях библиотеки и/или базового инструментария (это очень часто происходит с wxGTK). –

+0

Это пока не сказано, но TextCtrl может быть реализована путем использования собственного виджета. Но документы в этом немыслимы. Итак, большие пальцы вверх для подтверждения того, что TextCtrl - это собственный элемент управления. Хотя мне не повезло в рисовании RichTextCtrl ... – isync

0

В вашей функции, которая переопределяет метод краски базового класса, вызовите метод окраски базового класса перед вашим собственным кодом.

Для чего это стоит, вот как это сделать с C++

wxTextCtrl::OnPaint() 
+0

Ах, ладно. Но я не могу понять, как это сделать в WxPerl. Любой намек? Вызов $ self-> SUPER :: OnPaint() не работает. Также: будет ли Wx следить за тем, что краска базы уже была вызвана? Но кроме этого, кажется, у меня есть только доступ к базовому классу «new() .., а не к рисованию). (Наверное, из меня здесь дурак ...) – isync

+0

Извините, я ничего не знаю о wxPerl. Это похоже на сумасшедший язык! Хороший учебник perl должен рассказать вам, как вызвать метод в базовом классе. – ravenspoint

+0

Ну, кроме _ $ self-> SUPER :: OnPaint() _ (с SUPER, являющимся сокращением Perlish для «базового класса»), я также пробовал 'Wx :: TextCtrl :: OnPaint()', но это, казалось, ничего не делало, не бросало и не ошибалось, но и не оказывало никакого эффекта. Интересно переключиться между подклассом TextCtrl и RichtTextCtrl (с последним я закончил с линией, но текст не появился, а с TextCtrl - наоборот). Я получаю догадку, что «привязки WxPerl какого-то типа» в Wx являются неполными, когда дело доходит до OnPaint ... – isync

0

Я стараюсь действовать по совету VZ. Ниже приведена минимальная программа, предназначенная для создания RichTextCtrl и рисования линии по ней. Вместо этого он только рисует окно RichTextCtrl. Если я прокомментирую строку, начинающуюся с «self.rtc =», она вместо этого рисует только строку, а не RichTextContrl.

# sources: 
    # http://wiki.wxpython.org/VerySimpleDrawing 
    # https://github.com/wxWidgets/wxPython/blob/master/demo/RichTextCtrl.py 

import wx 
import wx.richtext as rt 

class DrawPanel(wx.Frame): 
    def __init__(self, *args, **kw): 
     wx.Frame.__init__(self, *args, **kw) 
     self.rtc = rt.RichTextCtrl(self,style=wx.VSCROLL|wx.HSCROLL|wx.NO_BORDER) 
     self.Bind(wx.EVT_PAINT, self.OnPaint) 

    def OnPaint(self, event=None): 
     dc = wx.PaintDC(self) 
     dc.Clear() 
     dc.SetPen(wx.Pen(wx.BLACK, 2)) 
     dc.DrawLine(0, 0, 50, 50) 

app = wx.App(False) 
frame = DrawPanel(None) 
frame.Show() 
app.MainLoop() 
Смежные вопросы