Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.72/25: Рейтинг темы: голосов - 25, средняя оценка - 4.72
5 / 5 / 2
Регистрация: 29.08.2012
Сообщений: 46

Мышь в виде перекрестия на весь PaintBox (Image)

27.01.2016, 16:12. Показов 5772. Ответов 58
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте! Использую PaintBox, но можно поговорить и об Image, т.к. почти одно и тоже)
Задача в следующем:

На своём PaintBox (далее PB) сверху (примерно 80% его высоты) у меня отведено под некий график, а в нижней части PB (20%) я вывожу другой график, который идейно связан с верхним. Т.е. каждая точка на нижнем графике "рассказывает" пользователю о состоянии соответствующей точки верхнего графика. Но зрительно проводить вертикаль между далеко отстоящими друг от друга графиками не всем пользователям позволит косоглазие ))) Поэтому возникла идея превратить мышь в вертикаль на всю картинку, которая будет точно показывать, какая точка нижнего графика соответствует какой точке верхнего. Ну, а горизонталь за компанию: значение оси Y показывать будет... хотя особой необходимости в ней нет... так что если от этого зависит решение, то горизонталью я готов пожертвовать )))

Можно использовать OnMouseMove и рисовать линии на PB. Но если перерисовывать всю картинку при каждом движении мышки на 1 пиксель - то PB нереально дёргается (как мониторы компьютеров, которые показывают по телевизору, только быстро), программа иногда вылетает, да и вообще, выглядит это не эстетично и ужасно...

Возникла идея создавать новый огромный курсор мыши в виде креста (ведь он не связан графически с PB и своим перемещением зарисовывать изображение на нём не будет). А поскольку расстояния от перекрестия до границ PB всегда будут разными, то создавать этот курсор надо каждый раз новый в OnMouseMove, а не просто загрузить курсор из файла размером в три монитора ))). Может, кто-то знает, как это сделать? Или у кого-то будет оригинальное гениальное решение? Смысл в том, чтоб рисовать крест не на PB и не удалять его, восстанавливая изображение под ним, после того, как мышь ушла в другое место. Заранее, спасибо.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
27.01.2016, 16:12
Ответы с готовыми решениями:

Скопировать картинку с PaintBox в Image
Помогите, пожалуйста. Нужно скопировать картинку с PaintBox в Image. C помощью CopyRect не получается.

Графические компоненты Image, Shape, Chart, PaintBox
Написать программу: Организовать выбор способа задания параллелограмма из списка: - по двум сторонам и углу между ними, - по двум...

Image во весь экран
Подскажите, как прописать чтобы изображение было на весь экран? то есть вообще форма скрывается и картина по всему экрану.

58
Практикантроп
 Аватар для nick42
4841 / 2726 / 534
Регистрация: 23.09.2011
Сообщений: 5,798
27.01.2016, 17:06
Лучший ответ Сообщение было отмечено Kvarcenar как решение

Решение

Когда-то писал программу с применением графиков ( TChart ), и понадобилась возможность использовать крестообразный курсор с лучами на все поле графика. Я использовал два шейпа ( TShape ) - прямоугольники с шириной и высотой соотв. 1 пксл. Видимость их определялась положением мыши (в зоне графиков или вне), а координаты рассчитывались, исходя из данных о позиции курсора и положения поля графиков (в обработчике Chart1MouseMove). Работоспособность вполне приемлемая и мороки немного.
0
5 / 5 / 2
Регистрация: 29.08.2012
Сообщений: 46
27.01.2016, 17:21  [ТС]
Поездил квадратным Шэйпом по ПэинтБоксу.... ))))
Имидж и ПБ - это такая гадость, что если их другим окном перекрыть, то при сворачивании перекрывающего окна на месте перекрытия рисунка уже нет...
Миниатюры
Мышь в виде перекрестия на весь PaintBox (Image)  
0
Практикантроп
 Аватар для nick42
4841 / 2726 / 534
Регистрация: 23.09.2011
Сообщений: 5,798
27.01.2016, 17:34
ПэйнтБокс, как я думаю, - на любителя. Стоит форму с ним сместить частично за пределы экрана, как нарисованное на нем стирается. Если можно без него обойтись, - лучше применять TImage или TPanel.
0
5 / 5 / 2
Регистрация: 29.08.2012
Сообщений: 46
27.01.2016, 17:45  [ТС]
TImage - с исчезанием ничем не отличается от PB. Использую PB, потому что он при перерисовке в потоке меньше глючит и дёргается, чем имидж (у меня картинка обновляется в реальном времени)... Тут уже у меня тонна текста программы написана под PB, так что менять его на что-то другое не хотелось бы.. если только явного преимущества не даст.. А что TPanel? Она разве для рисования? И нарисованное исчезать не будет? Чё-то сомневаюсь.. Я панели использую, чтоб радиобаттоны на них кидать, чтоб на одной плоскости несколько групп радиобаттонов независимых было... тогда их несколько штук выбирать можно, а не только какой-то один.. )) Кстати, проблема с исчезанием картинки - это ж, вроде, проблема всего Canvas-а, а не только имиджа или пэинтбокса.. В общем, остаётся надежда только на курсор мышки... надо его как-то огромным сделать... мышка на картинку не влияет..
0
Практикантроп
 Аватар для nick42
4841 / 2726 / 534
Регистрация: 23.09.2011
Сообщений: 5,798
27.01.2016, 18:06
Цитата Сообщение от Kvarcenar Посмотреть сообщение
TImage - с исчезанием ничем не отличается от PB
неправда.
1
5 / 5 / 2
Регистрация: 29.08.2012
Сообщений: 46
27.01.2016, 18:21  [ТС]
неправда.
Странно.. Был уверен, что исчезает.. Сейчас проверил - действительно, держится.. и даже шэйп не оставляет шлейфа.. Очень странно.. Но имидж в потоке сильнее дёргается. Это точно. Рядом ПэинтБокс и Имидж ставил, рисовал одно и то же и сравнивал, чтоб выбрать, что использовать, и выбрал ПэинтБокс.. В общем, если с мышиным перекрестием не разберусь - буду решать, мучиться ли с имиджем в потоке и иметь перекрестие или оставить ПэинтБокс и мучиться с перекрестием... В любом случае, за открытие с имиджем - спасибо!
0
Практикантроп
 Аватар для nick42
4841 / 2726 / 534
Регистрация: 23.09.2011
Сообщений: 5,798
27.01.2016, 19:15
Цитата Сообщение от Kvarcenar Посмотреть сообщение
имидж в потоке сильнее дёргается
DoubleBuffered = true;
0
place status here
 Аватар для gunslinger
3186 / 2220 / 640
Регистрация: 20.07.2013
Сообщений: 6,014
27.01.2016, 19:43
Лучший ответ Сообщение было отмечено Kvarcenar как решение

Решение

Пример ниже (на основе темы Overlay поверх полноэкранных приложений) позволяет рисовать "крестик" по размерам Image (когда курсор находится над ним).

cpp:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//---------------------------------------------------------------------------
 
#include <vcl.h>
#pragma hdrstop
 
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
HDC Display;
int x, y, a, b;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
  Display = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ImageMouseEnter(TObject *Sender)
{
  Image->Cursor = crCross;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ImageMouseLeave(TObject *Sender)
{
  Image->Cursor = crDefault;
  Refresh();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  DeleteDC(Display);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ImageMouseMove(TObject *Sender, TShiftState Shift, int X,
          int Y)
{
  Image->Refresh();
  a = (Width - ClientWidth) / 2;
  x = a + Image->Left + Left + X;
  b = Height - ClientHeight - a;
  y = b + Image->Top + Top + Y;
 
  int temp = Image->Left + Left + a;
  MoveToEx(Display, temp, y, (LPPOINT) NULL);
  LineTo(Display, temp + Image->Width, y);
  temp = Image->Top + Top + b;
  MoveToEx(Display, x, temp, (LPPOINT) NULL);
  LineTo(Display, x, temp + Image->Height);
}
//---------------------------------------------------------------------------
h:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//---------------------------------------------------------------------------
 
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <Vcl.Imaging.jpeg.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
    TImage *Image;
    void __fastcall ImageMouseEnter(TObject *Sender);
    void __fastcall ImageMouseLeave(TObject *Sender);
    void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
    void __fastcall ImageMouseMove(TObject *Sender, TShiftState Shift, int X, int Y);
 
private:    // User declarations
public:     // User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Миниатюры
Мышь в виде перекрестия на весь PaintBox (Image)  
1
place status here
 Аватар для gunslinger
3186 / 2220 / 640
Регистрация: 20.07.2013
Сообщений: 6,014
27.01.2016, 19:49
Можно обойтись без таймера, поэтому убрал его из кода выше.
0
5 / 5 / 2
Регистрация: 29.08.2012
Сообщений: 46
27.01.2016, 21:46  [ТС]
Цитата Сообщение от nick42 Посмотреть сообщение
DoubleBuffered = true;
Не помогает... И где эту строку писать? Я в событии FormActivate написал... Попытался перестроить программу под имидж - всё сломал )))) Почему-то простое изменение параметров функций с void F(TPaintBox *PB); на void F(TImage *PB); не помогло.. вообще перестало рисовать... так что без пошаговой отладки не обойтись... )))
Цитата Сообщение от gunslinger Посмотреть сообщение
Пример ниже (на основе темы Overlay поверх полноэкранных приложений) позволяет рисовать "крестик" по размерам Image (когда курсор находится над ним).
Спасибо. Интересная идея. Попробовал на ПэинтБоксе - линии замазывают изображенное на нём... Обидно... Может, кто-то про курсор мышки подскажет... Бо возиться с переходом на не менее глючный имидж не охота...
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
27.01.2016, 23:36
Цитата Сообщение от Kvarcenar Посмотреть сообщение
Имидж и ПБ - это такая гадость, что если их другим окном перекрыть, то при сворачивании перекрывающего окна на месте перекрытия рисунка уже нет...
Книги тоже гадость зачем их читать?
Но если эту заливную рыбу все же...
То можно узнать что сказанное про TImage вранье...
А что касается TPainBox то что бы такого не было нужно рисовать в событии OnPaint() а не где попало.
При необходимости перерисовки вызывать Invalidate() или InvalidateRect().

Добавлено через 6 минут
И обычно DoubleBuffered = true; достаточно.
1
place status here
 Аватар для gunslinger
3186 / 2220 / 640
Регистрация: 20.07.2013
Сообщений: 6,014
28.01.2016, 00:15
Что касается мерцания (хотя сам сильно не вникал):
WM_SYNCPAINT or how to produce flicker

I thought that my VCLFlickerReduce.pas unit was going to be abandoned because there are too many painting exceptions that I wasn't able to handle and even if I could have, it would have been impossible to keep the unit compatible with all the third party components. But last weekend I found the reason for most flicker related to realigning controls in the VCL. There is a message named WM_SYNCPAINT that Delphi 2007's Messages.pas doesn't even know. But this message is responsible for a lot of unintentional flicker that is generated by using the Align and Anchor properties.

Every time a control is resized it realigns all its children. For this the SetWindowPos API is used in TWinControl.SetBounds which is called for every realigned control. The SetWindowPos API invalidates the controls and posts a WM_ERASEBKGND and WM_PAINT to the message queue. But SetWindowPos does more. It not only invalidates the control, it also sends the WM_ERASEBKGND and WM_NCPAINT directly to the control without the way through the message loop. So the controls are erased and their border is painted while we are still in the realign process. After the realignment has finished the messages in the message queue are processed what sends another WM_ERASEBKGND and WM_PAINT to the control. Because there is a time difference between the first WM_ERASEBKGND from SetWindowPos and the second WM_ERASEBKGND/WM_PAINT from InvalidateRect, we see heavy flicker.

With this information I started doing some research in the PSDK documentation for SetWindowPos in order to find out if there is a way to prevent it from directly sending the messages to the controls. And there is a flag: SWP_DEFERERASE. It prevents SetWindowPos from sending a WM_SYNCPAINT message to the control. So what is WM_SYNCPAINT? Delphi 2007 doesn't know it (Messages.pas), but the PSDK does. The description of WM_SYNCPAINT says that it sends a WM_ERASEBKGND and/or WM_NCPAINT to the control's window procedure (what means that it does not use the message queue).

With this knowledge I added the SWP_DEFERERASE flag to the SetWindowPos call in SetBounds and started a test application. The result was amazing. While resizing the formular the controls were almost flicker free. Some days later I tried this with a huge real world application. This application has suffered a lot from the flicker. Resizing the main window was a no-go because the repainting of the formular took that much time that the mouse cursor was at a different location while the window was still not resized to the size that was specified by the the mouse 2 seconds ago. But after applying the SetBounds-patch I couldn't believe what I saw. The windows size followed the mouse position immediatelly like I would resize Notepad with no file loaded.

But then I saw something that made me think that all the work was for nothing. When I have an alBottom control and I shrink the formular's height and then restore it, all transparent groupboxes with alTop or Anchors-[akBottom], which are placed on a gradient-panel, are not repainted so their background is outdated and does not fit to the gradient on their left, top, right and bottom. But it took me only some minutes to find a solution for this. Using InvalidateRect with bErase=True on the already existing update region that SetWindowPos invalidated.

After having done this I added the patch to more applications and I haven't found a painting bug yet. Unfortunately the InvalidateRect with bErase=True causes some flicker but that is acceptable and in no way comparable with the flicker I had before. No WM_ERASEBKGND/WM_NCPAINT anymore while realigning. All painting is done when the controls are aligned and not earlier.

There is still some flicker and if you use PageControls you will experience a lot more flicker. But I haven't found the time to investigate into this. Setting the ParentBackground of the PageControl and every TabSheet meight help.
Вложения
Тип файла: zip VCLFlickerReduce.zip (3.1 Кб, 17 просмотров)
0
5 / 5 / 2
Регистрация: 29.08.2012
Сообщений: 46
28.01.2016, 00:48  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
что бы такого не было нужно рисовать в событии OnPaint()
Действительно. Перенёс рисовальные функции в OnPaint() - перестало исчезать изображение! Даже шейпом поводил по пэинтбоксу - он уже белых узоров не рисует! Спасибо большой. А чем OnPaint() особенный такой? Может, его особенность можно встраивать в функции рисования и вызывать их из любого места? Потому что при разных событиях надо рисовать и дорисовывать разные вещи. С кучей булевых переменных можно и через OnPaint() реализовать, но, может, можно без этого головняка?
Цитата Сообщение от gunslinger Посмотреть сообщение
Что касается мерцания (хотя сам сильно не вникал)
Так там же ж про делфи... Та и пусть мерцает. ))) Пэинтбокс в этом деле не такой заметный, как имидж - можно мириться. Почти незаметно..
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
28.01.2016, 01:17
Цитата Сообщение от Kvarcenar Посмотреть сообщение
А чем OnPaint() особенный такой?
Я бы сказал да это будет потыканием лени, да и я время зря потеряю...
Цитата Сообщение от Kvarcenar Посмотреть сообщение
Может, его особенность можно встраивать в функции рисования и вызывать их из любого места?
Цитата Сообщение от Avazart Посмотреть сообщение
При необходимости перерисовки вызывать Invalidate() или InvalidateRect().
0
5 / 5 / 2
Регистрация: 29.08.2012
Сообщений: 46
28.01.2016, 01:26  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
да это будет потыканием лени
Ок. Не будем ничем тЫкать в лень... ))) Вашему уму чуток деликатности не повредил бы.. В любом случае, спасибо, Вы очень помогли. Картинка не исчезает, перекрестие её не затирает. Шэйпы подёргиваются, поэтому, возможно, переделаю вторым предложенным способом. Проблема, можно сказать, решена. Хотя и не так, как планировалось.. Всем спасибо за участие!
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
28.01.2016, 15:46
Ну а зачем вам шейпы? рисуйте прям на канве все сразу.
0
5 / 5 / 2
Регистрация: 29.08.2012
Сообщений: 46
28.01.2016, 16:04  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
Ну а зачем вам шейпы? рисуйте прям на канве все сразу.
Я ж говорю, если перерисовывать всю картинку при каждом движении мышки на пиксель - то вся картинка дёргается сильно. Да и программа изредка вылетает с ошибкой "отказано в доступе по какому-то адресу". А отследить эту ошибку нереально, потому что если ставить брейк-поинт на онмаусмув - то задолбёшься из окна редактора на запущенный проект переключаться, да и не выскочит эта ошибка никогда, если так медленно всё делать... поэтому рисовать две белых линии на пэинтбоксе - не вариант. А с шэйпами нормально всё. Только вот, онклик события на них нету... а на пэинтбоксе оно у меня обрабатывается... теперь с шэйпами оно никогда не происходит, потому что мышка находится на шэйпе постоянно и чтоб кликнуть по пэинтбоксу - надо мастерство моторики продемонстрировать.. у меня ещё не получилось )))))) так что, вероятно, сделаю предложенным оверлеем..
0
Практикантроп
 Аватар для nick42
4841 / 2726 / 534
Регистрация: 23.09.2011
Сообщений: 5,798
28.01.2016, 16:31
Цитата Сообщение от Kvarcenar Посмотреть сообщение
чтоб кликнуть по пэинтбоксу - надо мастерство моторики продемонстрировать.. у меня ещё не получилось
Установите свойство шейпов Enabled в false - и мастерство не потребуется.
1
5 / 5 / 2
Регистрация: 29.08.2012
Сообщений: 46
28.01.2016, 16:52  [ТС]
Цитата Сообщение от nick42 Посмотреть сообщение
Установите свойство шейпов Enabled в false - и мастерство не потребуется.
Прикольно! А я думал, Enabled просто неактивным делает.. а оно, оказывается, ещё и насквозь тыкать позволяет! Спасибко! ))))
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
28.01.2016, 16:52
Помогаю со студенческими работами здесь

Как сместить Canvas в PaintBox не смещая PaintBox?
Как сместить например на 3 пикселя весь рисунок в PaintBox, не изменяя при этом размеров и позиции PaintBox?

Растянуть Image на весь Glyph SpeedButton-а
Такой кодdynamic_cast&lt; TImage*&gt;(Form13-&gt;FindComponent(&quot;I160&quot;))-&gt;Width=SB-&gt;Width; dynamic_cast&lt;...

Acronis True Image тоже весь жёсткий диск форматирует
Acronis True Image тоже ВЕСЬ жёсткий диск форматирует, если конфигурация разделов изменилась? Эта проблема появилась когда я везде...

Вывести весь текст словами в виде количественного числительного
Задано некоторое натуральное число k. Требуется вывести весь текст словами в виде количественного числительного, которое означает заданное...

Вывести весь текст словами в виде количественного числительного
Задано некоторое натуральное число k. Требуется вывести весь текст словами (например, при k=5 вывод имеет вид &quot;пять&quot;, при k=123...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru