На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
  
> Проблема с PaintBox , как вывести изображение?
    Добрый день.
    Помогите решить проблемы!
    Есть простенькая программа, рисующая круги в PaintBox... И всё вроде бы работало нормально, пока я не заметил, что если какое либо приложение нашло на мою форму то изображение "затирается"... Я поискал ответа на этом форуме, но там всё как то слишком обще сказано и не понятно мне... =) И вторая проблема - сохранение изображения из PaintBox. Поиск помог отрыть кусок кода для сохранения. Вот он:
    ExpandedWrap disabled
      void __fastcall paintBoxToFile( TPaintBox * aPaintBox, AnsiString aFileName ){
          // Создаем bitmap
         Graphics::TBitmap * bmp = new Graphics::TBitmap();
         try{
             // Устанавливаем размеры и формат
            bmp->PixelFormat = pf24bit;
            bmp->Height = aPaintBox->ClientHeight;
            bmp->Width = aPaintBox->ClientWidth;
             // Запоминаем старый handle
            HANDLE oldHandle = aPaintBox->Canvas->Handle;
            try{
                // Устанавливаем handle bitmap'а
               aPaintBox->Canvas->Handle = bmp->Canvas->Handle;
                // Заставляем вывести изображение
                // Если не будет обработчика, то на этом месте программа упадет
               aPaintBox->OnPaint( aPaintBox );
            }
            __finally{
                // Восстанавливаем handle
               aPaintBox->Canvas->Handle = oldHandle;
            }
             // Сохраняем в файл
            bmp->SaveToFile( aFileName );
         }
         __finally{
             // Удаляем bitmap
            delete bmp;
         }
      }


    Но объясните мне как заставить PaintBox вывести изображение? Потому что файл сохраняется, но он пустой... То есть белый.
    Заранее спасибо!
      Цитата Yura93 @
      если какое либо приложение нашло на мою форму то изображение "затирается"...
      Потому что файл сохраняется, но он пустой...

      Значит обработчик OnPaint реализован неправильно
      Сообщение отредактировано: leo -
        Суть такая:
        - создаёшь временный битмап bmp размерами с пайнтбокс
        - создаёшь некий метод Draw(), который рисует именно на этом битмапе
        - в событии PaintBox->OnPaint() просто отображаешь этот битмап на канве пайнтбокса PaintBox->Canvas->Draw(0, 0, bmp)
        - ну а сохранить битмап в файл проблему не составит
        Сообщение отредактировано: Сан Иваныч -
          Цитата Сан Иваныч @
          Суть такая:
          ...

          А какой тогда смысл вообще юзать PaintBox ? Проще заменить его на TImage - рисуешь один раз картинку, при этом автоматом создаться битмап, и перерисовывается автоматически без всяких OnPaint, и об удалении битмапа думать не нужно
            да, как предложил leo лучше сделай. PaintBox постоянно перерисовываеться, а c TImage нарисовал и забыл ;)
              PaintBox в данном случае имеет смысл, если недолгая отрасовка, и смысла нету картинку держать, или она хранится другим способом, например чараз api или какой-то специфической компонентой, или библиотекой. При этом можно повесить обработчик и рисовать не всю область, а только то, что нуждается в отрисовке при желании. В простом вар-те - да, лучше положить timage и не извращаться.
                Вы меня не так поняли! :lol: PaintBox у меня используется как простейший графический редактор.
                Из всех возможный событий у меня используются только OnMouseDown, OnMouseUp, OnMouseMove. Если ны нажал и водишь мышкой по PaintBox то рисуется след из кругов. Их цвет и размер можно менять. А я хочу чтобы нарисованное сообщение можно было сохранить. И чтобы оно не затиралось другими приложениями.
                В данном случае Image не подходит потому что у него нет свойство OnMouseMove.
                И если надо вот кусок кода отвечающий за отрисовку:
                ExpandedWrap disabled
                  void __fastcall TForm1::PaintBox1MouseMove(TObject *Sender, TShiftState Shift, int X,
                            int Y)
                  {
                  if(MouseD){
                   
                      Size=StrToInt(Edit1->Text);
                      if(CheckBox3->Checked){
                          PenW=StrToInt(Edit2->Text);
                      }
                      else{
                          PenW=0;
                          PenC=Panel2->Color;
                      }
                      PaintBox1->Canvas->Brush->Color=Panel2->Color;
                      PaintBox1->Canvas->Pen->Color=PenC;
                      PaintBox1->Canvas->Pen->Width=PenW;
                      if(RadioGroup1->ItemIndex==0){
                          PaintBox1->Canvas->Ellipse(X - Size,Y - Size, X + Size, Y + Size);
                      }
                      else{
                          PaintBox1->Canvas->Rectangle(X - Size,Y - Size, X + Size, Y + Size);
                      }
                  }
                  }
                Сообщение отредактировано: Yura93 -
                  Цитата Yura93 @
                  В данном случае Image не подходит потому что у него нет свойство OnMouseMove.

                  У тебя какой Builder ? на 6 ке есть.

                  PS. Можно легко научить его этому
                  Так
                  или так :

                  ExpandedWrap disabled
                    // *.h файл
                    class TForm1 : public TForm
                    {
                    //...
                    public:     // User declarations
                            __fastcall TForm1(TComponent* Owner);
                            TWndMethod OldWndProc;
                            void __fastcall NewWndProc(TMessage &Msg);
                    };
                     
                    // *.cpp файл
                    //---------------------------------------------------------------------------
                    __fastcall TForm1::TForm1(TComponent* Owner)
                            : TForm(Owner)
                    {
                    OldWndProc = Image1->WindowProc;
                    Image1->WindowProc = NewWndProc;
                    }
                    //---------------------------------------------------------------------------
                    void __fastcall TForm1::NewWndProc(TMessage &Msg)
                    {
                    POINT p;
                    switch (Msg.Msg)
                    {
                    case WM_MOUSEMOVE :
                    {
                    p.x = Msg.LParamLo;
                    p.y = Msg.LParamHi;
                    }
                    case WM_DESTROY :
                    {
                    Image2->WindowProc = OldWndProc;
                    break;
                    }
                    }
                    OldWndProc(Msg);
                    }
                  Сообщение отредактировано: sh_grumpy -
                    CodeGear2009
                      Цитата Yura93 @
                      Вы меня не так поняли! :lol: PaintBox у меня используется как простейший графический редактор.
                      Из всех возможный событий у меня используются только OnMouseDown, OnMouseUp, OnMouseMove

                      Это ты не так понял назначение TPaintBox, который в отличие от TImage, нигде не хранит нарисованное изображение и поэтому оно должно каждый раз, целиком перерисовываться, и нигде нибудь, а именно в OnPaint. А если рисовать в PaintBox'е не в OnPaint, а по каким-то "левым" событиям, то при любой перерисовке окна, инициированной виндой (при перекрытии, изменении размеров и т.п.) - все твои "художества" потеряются, что собс-но у тебя и происходит

                      Поэтому тебе нужен именно TImage, который сохраняет все, что тобой нарисовано, в своем Picture.Bitmap, и соответственно автоматически отображает этот битмап на экране по виндовым запросам WM_PAINT. И события OnMouse... в TImage должны быть, по крайней мере в BCB 6 они есть, и поэтому твое заявление
                      Цитата Yura93 @
                      В данном случае Image не подходит потому что у него нет свойство OnMouseMove

                      - скорее всего неверно
                      Сообщение отредактировано: leo -
                        А что должно быть в событии OnPaint?
                          Цитата Yura93 @
                          А что должно быть в событии OnPaint?

                          то что ты хочешь видеть в своем PainBox'е.
                            Цитата popsa @
                            то что ты хочешь видеть в своем PainBox'е.

                            Ёмко но не понятно... Приведите пример кода...
                              к примеру напиши в своем примере в обработчике OnPaint ;)
                              ExpandedWrap disabled
                                PaintBox1->Canvas->Pen->Color=clRed;
                                PaintBox1->Canvas->Pen->Width=3;
                                PaintBox1->Canvas->Rectangle(40,30, 100, 100);
                                Стоп! Когда наступает событие OnPaint?
                                  Цитата Yura93 @
                                  Стоп! Когда наступает событие OnPaint?

                                  каждый раз, когда происходит перерисовка твоего PaintBox'а.
                                    Цитата Yura93 @
                                    Стоп! Когда наступает событие OnPaint?

                                    Когда винда или твоя прога просят полностью или частично перерисовать прямоугольник, занятый твоим PaintBox'ом. При этом то, что ты рисовал ранее стирается и нужно все рисовать заново. Если дружишь с аглицким, то глянь справку по TPaintBox::OnPaint и особенно Example2 - пример того как делать нельзя, как раз твой случай ;)

                                    Добавлено
                                    PS: Говоря "по научному" PaintBox рисует изображение непосредственно на "канве экрана" (screen buffer). Поэтому когда PaintBox перекрывается другим окном, то это место канвы экрана перерисовывается другим окном и старое изображение от твоего PaintBox'а ес-но затирается = пропадает. Соотв-но, когда это окно закрывается\перемещается, твой PaintBox всплывает наверх и винда просит его перерисовать соответсвующую область экрана заново - шлет ему сообщение WM_PAINT, которое вызывает событие OnPaint. Если ты в обработчике OnPaint ничего не нарисуешь, то соотв-но получишь белый прямоугольник.

                                    TImage, в отличие от PaintBox'a, рисует изображение не прямо на экране, а в битмапе (по умолчанию) и затем по требованию WM_PAINT просто копирует весь битмап или его часть на экран. Соотв-но, при всяких перекрытиях окон с битмапом ничего не происходит и изображение никуда не пропадает, и никаких OnPaint не нужно, т.к.отрисовка битмапа на экране происходит автоматически
                                    Сообщение отредактировано: leo -
                                      Цитата Yura93 @
                                      Стоп! Когда наступает событие OnPaint?



                                      Когда винде надо отрисовать твоё окно. Причём там есть фишка, что когда приходит onPaint - не обязательно его отрисовывать во всех случаях, т.к. если например будешь окно таскать по экрану - то увидишь, что оно не перерисовывается постоянно, а просто таскается, но если там будет стоять твой обработчик - то ему событие будет приходить и ты будешь перерисовывать. Если делать на api - то там есть такая фишка как begin_paint кажется, вот с помощью связки begin_paint и end_paint - там формировалась структура и с её помошью можно было определить что нужно рисовать и нужно ли, аналогию в VCL я не знаю, но если заметишь, что твоё приложение медленно рисуется при таскании окна и это будет критично, можешь туда копнуть. К сожалению, я на память всё не помню, надо код свой смотреть, чтобы детали рассказать.
                                        Цитата brother79 @
                                        Причём там есть фишка, что когда приходит onPaint - не обязательно его отрисовывать во всех случаях, т.к. если например будешь окно таскать по экрану - то увидишь, что оно не перерисовывается постоянно, а просто таскается, но если там будет стоять твой обработчик - то ему событие будет приходить и ты будешь перерисовывать

                                        Ничего подобного, WM_PAINT и соотв-но OnPaint приходят только тогда, когда задана конкретная область, которую нужно перерисовать. В begin_paint эта область задается прямоугольником lpPaint->rcPaint, в VCL этот прямоугольник = Canvas->ClipRect

                                        Но все - это излишние подробности, т.к. TPaintBox, несмотря на свое обманчивое название, совершенно не подходит для "простейшего графического редактора", т.к. он не запоминает нарисованное изображение и для того, чтобы оно не терялось при перерисовках, придется рисовать не сразу на экран, а в битмап и затем копировать этот битмап на экран в OnPaint. Спрашивается - зачем городить огород, если все это уже реализовано в TImage ?
                                        Сообщение отредактировано: leo -
                                          Я придумал как сохранять изображения! Если что то было нарисовано на PaintBox то тоже самое рисуется и на невидимом Image... Но это не работает при Resize и я не знаю что нужно написать чтобы в OnPaint картинка из Image рисовалась на PaintBox...
                                            Цитата Yura93 @
                                            Я придумал как сохранять изображения!

                                            :wacko:
                                            За тебя уже Борланд все давно придумал - юзай TImage вместо TPainBox и не морочь голову, с чего ты взял, что у него нет событий OnMouse.. ? В 6-м билдере точно есть, а у тебя какой ?

                                            Добавлено
                                            Цитата Yura93 @
                                            что нужно написать чтобы в OnPaint картинка из Image рисовалась на PaintBox...

                                            Ну если ты извращенец, то напиши
                                            ExpandedWrap disabled
                                                PaintBox1->Canvas->Draw(0,0,Image1->Picture->Bitmap);


                                            Добавлено
                                            PS: События OnMouse есть у всех наследников TControl, как их может не быть у TImage - загадка :wacko:
                                            Сообщение отредактировано: leo -
                                              :wall: Да-да-да... Все кто говорил что я - слепой и у Image есть события OnMouse были правы! Извините! Но!! Я всё переделал в человеческий код. Теперь всё рисуется непосредственно на Image. Должно рисоваться... Я проверял "точкой останова" (если не ошибаюсь) и заметил что при щелчке на Image событие OnMouse не обрабатывается... В чём дело?

                                              Добавлено
                                              Ах да! Если надо то вот код:
                                              ExpandedWrap disabled
                                                void __fastcall TForm1::Image1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
                                                          int X, int Y)
                                                {
                                                MouseD=true;
                                                }
                                                //---------------------------------------------------------------------------
                                                 
                                                void __fastcall TForm1::Image1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift,
                                                          int X, int Y)
                                                {
                                                MouseD=false;
                                                }
                                                //---------------------------------------------------------------------------
                                                 
                                                void __fastcall TForm1::Image1MouseMove(TObject *Sender, TShiftState Shift, int X,
                                                          int Y)
                                                {
                                                Size=StrToInt(Edit1->Text);
                                                    if(MouseD){
                                                        Image1->Canvas->Brush->Color=Panel2->Color;
                                                        if(CheckBox3->Checked){
                                                            Image1->Canvas->Pen->Color=Panel6->Color;
                                                            Image1->Canvas->Pen->Width=StrToInt(Edit2->Text);
                                                        }
                                                        else{
                                                            Image1->Canvas->Pen->Color=Panel2->Color;
                                                            Image1->Canvas->Pen->Width=0;
                                                        }
                                                        if(RadioGroup1->ItemIndex==1){
                                                            Image1->Canvas->Ellipse(X-Size,Y-Size,X+Size,Y+Size);
                                                        }
                                                        else{
                                                            Image1->Canvas->Rectangle(X-Size,Y-Size,X+Size,Y+Size);
                                                        }
                                                    }
                                                }
                                                //---------------------------------------------------------------------------

                                              Может кто-нибудь увидит тут серьёзную ошибку?
                                                Отслеживать MouseDown\Up и устанавливать флаг MouseD никчему, т.к. признак зажатия кнопки передается в параметре Shift обработчика MouseMove
                                                ExpandedWrap disabled
                                                    //if(MouseD){
                                                    if (Shift.Contains(ssLeft)) { //перемещение мыши с нажатой левой кнопкой
                                                    ...
                                                Сообщение отредактировано: leo -
                                                  leo, спасибо я исправил. Но всё равно программа не реагирует не вождение мышью по Image и не приходит туда сколько бы я не кликал и не водил мышью.
                                                  Теперь код выглядит так:
                                                  ExpandedWrap disabled
                                                    void __fastcall TForm1::Image1MouseMove(TObject *Sender, TShiftState Shift, int X,
                                                              int Y)
                                                    {
                                                    Size=StrToInt(Edit1->Text);
                                                        if(Shift.Contains(ssLeft)){
                                                            Image1->Canvas->Brush->Color=Panel2->Color;
                                                            if(CheckBox3->Checked){
                                                                Image1->Canvas->Pen->Color=Panel6->Color;
                                                                Image1->Canvas->Pen->Width=StrToInt(Edit2->Text);
                                                            }
                                                            else{
                                                                Image1->Canvas->Pen->Color=Panel2->Color;
                                                                Image1->Canvas->Pen->Width=0;
                                                            }
                                                            if(RadioGroup1->ItemIndex==1){
                                                                Image1->Canvas->Ellipse(X-Size,Y-Size,X+Size,Y+Size);
                                                            }
                                                            else{
                                                                Image1->Canvas->Rectangle(X-Size,Y-Size,X+Size,Y+Size);
                                                            }
                                                        }
                                                    }
                                                    Цитата Yura93 @
                                                    Но всё равно программа не реагирует не вождение мышью по Image и не приходит туда сколько бы я не кликал и не водил мышью

                                                    Ну, не знаю, у меня нормально реагирует и рисует
                                                    Может обработчик в инспекторе не присвоил, или неcколько Image создал - присвоил одному, а водишь мышью по другому - казусы разные бывают ;)
                                                      Цитата leo @
                                                      Может обработчик в инспекторе не присвоил

                                                      Что это значит?
                                                        Так... Ну ошибку я исправил... Почему то глюк был из-за того что Image лежал на Panel а она видимо автоматически кладётся поверх... Но теперь почему то не работает функция формы OnResize... Вот код:
                                                        ExpandedWrap disabled
                                                          {
                                                          void __fastcall TForm1::FormResize(TObject *Sender){
                                                           
                                                          Image1->Width=Form1->ClientHeight-16;
                                                          Image1->Height=Form1->ClientWidth-133;
                                                          Image1->Top=8;
                                                          Image1->Left=8;
                                                           
                                                          }
                                                          //---------------------------------------------------------------------------

                                                        Но тут важно то что Image в принципе не меняет своих размеров...
                                                        Сообщение отредактировано: Yura93 -
                                                          Цитата Yura93 @
                                                          а она видимо автоматически кладётся поверх...

                                                          :no:
                                                          Если все нормально сделано, то без разницы где лежит Image, на форме или на панели

                                                          Цитата Yura93 @
                                                          Но тут важно то что Image в принципе не меняет своих размеров...

                                                          :no:
                                                          Просто размер TImage и размер битмапа это не одно и то же. Размер хранимого изображения определяется размером битмапа Image->Picture->Bitmap. Если битмап создается автоматически при первом рисовании, то его размер устанавливается = размеру Image. В свою очередь размер Image определяет размер видимого изображения на экране. Если Image.AutoSize = false, то после создания битмапа размеры Image и Bitmap не привязаны друг к другу. Поэтому при уменьшении размера Image видимое изображение будет уменьшаться (просто выводится не весь хранимый битмап, а только его часть). А вот при увеличении размера Image видимое изображение ес-но не может быть больше размера самого битмапа (размер рамки Image увеличивается, а размер битмапа остается тем же). Ну а если Image.AutoSize = true, то изменение размеров самого Image вообще не работает (размер = битмапу) и для ресайзинга изображения нужно изменять размер Image->Picture->Bitmap.

                                                          Поэтому сам думай, как должна вести себя картинка при изменении размеров. Если она должна всегда соответсвовать размеру окна и обрезаться при его уменьшении, то самое просто установить Image.AutoSize = true и в FormResize изменять не размеры Image, а размеры Image->Picture->Bitmap

                                                          PS: Top и Left при резайзе не изменяются, поэтому незачем их переустанавливать
                                                          Сообщение отредактировано: leo -
                                                            Поменял AutoSize на false и всё равно ничего не работает....
                                                              Цитата Yura93 @
                                                              Поменял AutoSize на false и всё равно ничего не работает....

                                                              Значит, не судьба :D
                                                              Насчет AutoSize и соотношение размеров Image и Bimap я уже тебе все "разжевал", осталось еще проверить св-ва Align и Constraints.
                                                              Плюс бросить дурную превычку тыкать мышой и менять значение св-в, не понимая как они работают и на что влияют. Сначала следует почитать справочку или умные книжки, а затем уже тыкать со знанием дела ;)
                                                                Constraints и Align я не менял! Align = none, Constraints не изменено.
                                                                  В таком случае, конкретно говори, что не работает и приводи код - как говориться "экстрасенсы в отпуске" ;)
                                                                  Повторяю: если AutoSize = false, то при уменьшении размеров Imаge относительно первоначального, видимое изображение должно уменьшаться, а при увеличении сверх исходного - не должно, т.к. битмап при этом автоматически не увеличивается и его размер остается тем же.
                                                                  Чтобы размер Image и Bitmap всегда совпадали, поставь AutoSize = true и вместо размеров Image изменяй размеры Image->Picture->Bitmap. Все это я уже разжевал в #28, что не понятно ?
                                                                    Цитата Yura93 @
                                                                    Так... Ну ошибку я исправил... Почему то глюк был из-за того что Image лежал на Panel а она видимо автоматически кладётся поверх... Но теперь почему то не работает функция формы OnResize... Вот код:
                                                                    ExpandedWrap disabled
                                                                      {
                                                                      void __fastcall TForm1::FormResize(TObject *Sender){
                                                                       
                                                                      Image1->Width=Form1->ClientHeight-16;
                                                                      Image1->Height=Form1->ClientWidth-133;
                                                                      Image1->Top=8;
                                                                      Image1->Left=8;
                                                                       
                                                                      }
                                                                      //---------------------------------------------------------------------------

                                                                    Но тут важно то что Image в принципе не меняет своих размеров...

                                                                    издеваешься?
                                                                    ExpandedWrap disabled
                                                                      {
                                                                      void __fastcall TForm1::FormResize(TObject *Sender){
                                                                       
                                                                      Image1->Width=Form1->ClientHeight-16;  // Width = Height ??
                                                                      Image1->Height=Form1->ClientWidth-133; // Height = Width ??
                                                                      Image1->Top=8;
                                                                      Image1->Left=8;
                                                                       
                                                                      }
                                                                      //---------------------------------------------------------------------------

                                                                    исправь и проверь...
                                                                    у тя Image на все форму? у всех компонентов есть свойство Align. По эксперементируй(alClient) может это то что тебе надо?...
                                                                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                    0 пользователей:


                                                                    Рейтинг@Mail.ru
                                                                    [ Script execution time: 0,0793 ]   [ 16 queries used ]   [ Generated: 13.06.25, 17:16 GMT ]