| Правила | Регистрация | Пользователи | Сообщения за день |  Справка по форуму | Файлообменник |

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > Почему не удается подключить GDIplus.dll к VBA?

Почему не удается подключить GDIplus.dll к VBA?

Ответ
Поиск в этой теме
Непрочитано 16.02.2023, 17:10 #1
Почему не удается подключить GDIplus.dll к VBA?
МишаИнженер
 
Регистрация: 14.12.2008
Сообщений: 1,079

При подключении библиотеки GDIplus.dll к VBA появляется ошибка.
Почему не удается подключить GDIplus.dll к VBA?
Есть ли способ использовать функции GDIPlus.dll в коде VBA?
Какие еще можно подключить библиотеки чтобы начать рисовать на формах UserForm VBA?

Миниатюры
Нажмите на изображение для увеличения
Название: Подключение GDIplus.dll к VBA.png
Просмотров: 72
Размер:	32.0 Кб
ID:	253424  Нажмите на изображение для увеличения
Название: Ошибка при подключении GDIplus.dll к VBA.png
Просмотров: 71
Размер:	20.2 Кб
ID:	253425  

Просмотров: 3257
 
Непрочитано 16.02.2023, 18:06
#2
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,052


кинуть на форму Images и рисовать через декларируемые апишные функции, насколько помню.. еще то развлечение)
Сергей812 вне форума  
 
Непрочитано 18.02.2023, 00:38
#3
Александр Ривилис

программист, рыцарь ObjectARX
 
Регистрация: 09.05.2005
Киев
Сообщений: 2,408
Отправить сообщение для Александр Ривилис с помощью Skype™


Цитата:
Сообщение от МишаИнженер Посмотреть сообщение
Почему не удается подключить GDIplus.dll к VBA?
Почитай какого типа dll можно использовать в VBA - вопросы отпадут.
Александр Ривилис вне форума  
 
Непрочитано 18.02.2023, 01:16
#4
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,052


даже в древней версии .Net Framework 1.1 (выпущенной 20 лет назад) есть классы, реализующие поддержку вызова API функций графического интерфейса для рисования. В VBA за эти годы ничего не изменилось - все ручками, ручками)

----- добавлено через ~35 мин. -----
Например, в VBA начертить эллипс на форме

Код:
[Выделить все]
Option Explicit

' Функция получения дескриптора окна
Private Declare PtrSafe Function FindWindow Lib "USER32" Alias "FindWindowA" _
  (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr

' Функция получения дескриптора для клиентской области указанного окна
Private Declare PtrSafe Function GetDC Lib "USER32" (ByVal HWnd As LongPtr) As Long

' Функция рисования эллипса, вписанного в указанный прямоугольник
Public Declare PtrSafe Function Ellipse Lib "gdi32" (ByVal HDc As LongPtr, _
  ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long

' Функция освобождения контекста устройства
Private Declare PtrSafe Function ReleaseDC Lib "User32.dll" (ByVal HWnd As LongPtr, _
  ByVal HDc As LongPtr) As LongPtr


Public Sub Test001()
  ' Получаем дескриптор окна формы
  Dim lHWnd As LongPtr: lHWnd = FindWindow(vbNullString, UserForm1.Caption)
  ' Получаем дескриптор для клиентской области окна
  Dim lHDc As Long: lHDc = GetDC(lHWnd)
  ' Рисуем эллипс
  Ellipse lHDc, 10, 10, 50, 50
  ' Освобождаем контекст устройства
  ReleaseDC lHWnd, lHDc
End Sub
при этом еще надо учитывать, что декларации API функций для 32 и 64-битных приложений будет отличаться.

Последний раз редактировалось Сергей812, 18.02.2023 в 01:53.
Сергей812 вне форума  
 
Автор темы   Непрочитано 18.02.2023, 08:23
#5
МишаИнженер


 
Регистрация: 14.12.2008
Сообщений: 1,079


Удалось начертить линии на UserForm, посмотрите файл Excel.
Но проблема теперь заключается в том, что начальная точка отсчета находится в левом ВЕРХНЕМ углу и ось Y направлена вниз.
Есть функция TranslateTransform, которая переносит точку начала координат в другую точку.
Попытался применить эту функцию в коде и появляется ошибка что "Функция не найдена в gdiplus.dll".
Как исправить эту ошибку?
Миниатюры
Нажмите на изображение для увеличения
Название: Ошибка вызова TranslateTransform.png
Просмотров: 50
Размер:	47.9 Кб
ID:	253478  Нажмите на изображение для увеличения
Название: Черчение на форме UserForm.png
Просмотров: 49
Размер:	56.8 Кб
ID:	253480  
Вложения
Тип файла: zip Матрицы_GDI.zip (54.0 Кб, 28 просмотров)
МишаИнженер вне форума  
 
Непрочитано 18.02.2023, 09:25
#6
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,052


подозреваю, что при вашей нелюбви к чтению документации неправильно задекларировали функцию)
Сергей812 вне форума  
 
Автор темы   Непрочитано 18.02.2023, 10:57
#7
МишаИнженер


 
Регистрация: 14.12.2008
Сообщений: 1,079


Немного поменял декларацию функции TranslateTransform согласно описанию данной функции на сайте Microsoft. Добавил пользовательский тип Status, (посмотрите картинки)
Но при вызове функции опять появляется таже ошибка
Код:
[Выделить все]
Private Sub UserForm_Initialize()
Dim retVal As Status
'Get hWndForm
   hWndForm = FindWindow(vbNullString, Me.Caption)
   hDCForm = GetDC(hWndForm)
   retVal = GdipTranslateTransform(hDCForm, 0, 50)
'Initiate GDI+
   Call InitGDI
End Sub
Где можно посмотреть какое название имеет эта функция TranslateTransform в файле gdiplus.dll?
Правильно ли решение, что параметр "optional" можно не описывать при декларации функции?
Миниатюры
Нажмите на изображение для увеличения
Название: Параметры функции TranslateTransform.png
Просмотров: 34
Размер:	34.3 Кб
ID:	253482  Нажмите на изображение для увеличения
Название: Декларация функции TranslateTransform.png
Просмотров: 34
Размер:	27.0 Кб
ID:	253483  
Вложения
Тип файла: zip Матрицы_GDI.zip (54.0 Кб, 26 просмотров)
МишаИнженер вне форума  
 
Автор темы   Непрочитано 18.02.2023, 12:14
#8
МишаИнженер


 
Регистрация: 14.12.2008
Сообщений: 1,079


Удалось запустить метод TranslateTransform поместив вызов в функцию вычерчивания линии:
Код:
[Выделить все]
Public Sub gLine(ByVal hDC As LongPtr, ByVal penColor As Long, ByVal penAlpha As Long, thickness As Long, _
                 ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long)
Dim hGraphics As LongPtr, hPen As LongPtr, lRes As Long
Dim retVal As Status, MOrd As MatrixOrder
   If GdipToken <> 0 And GdipCreateFromHDC(hDC, hGraphics) = 0 Then
      MOrd = MatrixOrderAppend
      retVal = GdipTranslateWorldTransform(hGraphics, 0#, 50#, MOrd)
      If penAlpha < 0 Then penAlpha = 0
      If penAlpha > 100 Then penAlpha = 100
      lRes = GdipCreatePen1(ConvertColor(penColor, penAlpha), thickness, &H2&, hPen)
      If hPen <> 0 Then
        lRes = GdipSetSmoothingMode(hGraphics, SmoothingModeAntiAlias)
        lRes = GdipDrawLineI(hGraphics, hPen, X1, Y1, X2, Y2)
        GdipDeletePen (hPen)
      End If     
      Call GdipDeleteGraphics(hGraphics)
   End If
End Sub
Это пришлось сделать потому что в качестве параметра этой функции надо указывать не дескриптор UserForm, а дескриптор объекта Grafix, который создается в функции вычерчивания линии.
Функция вызывается нормально, правда ничего не делает и возвращает состояние "сбой при выполнении".
Изменить ТЕКСТОВЫЙ режим черчения на форме (начало координат слева сверху) на ИЗОМЕТРИЧЕСКИЙ (начало координат слева снизу) не получается.
Есть ли возможность настроить ИЗОМЕТРИЧЕСКИЙ режим черчения на UserForm VBA?
И еще:
Получается что при рисовании каждой линии создается новый объект Grafix который вычерчивает эту линию на форме и потом этот объект удаляется, а линия остается.
А в какой контейнер записывается эта линия? Так как при рисовании следующей линии предыдущие не пропадают с экрана.
Мне в будущем надо будет постоянно вызывать этот контейнер для отрисовки, так как надо показывать ДИНАМИЧЕСКУЮ отрисовку линии на форме. То есть пока не указана конечная точка линии, на форме должна всегда чертиться, поверх всех остальных линий, линия от начальной точки до курсора мышки. То есть при перемещении мышки по форме в методе MouseMove надо перерисовывать картинку на форме и поверх этой картинки чертить линию от начальной точки до курсора мышки. Как вызвать метод перерисовки формы, чтобы заново чертились все линии до момента черчения новой линии?
Эти задачи надо решить для удобства черчения на UserForm.
Есть ли способ решения этих задач?
Вложения
Тип файла: zip Матрицы_GDI.zip (58.2 Кб, 26 просмотров)
МишаИнженер вне форума  
 
Непрочитано 18.02.2023, 17:05
#9
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,052


Цитата:
Сообщение от МишаИнженер Посмотреть сообщение
Есть ли способ решения этих задач?
хранить всю информацию и в обработчике события Paint отрисовывать заново. Причем в VBA WinForms этого обработчика события нет, насколько помню. Поэтому еще и хук (это не ругательство, если что) придется ставить на это событие.
Сергей812 вне форума  
 
Непрочитано 19.02.2023, 05:39
1 | #10
Нубий-IV

Инженер-философ
 
Регистрация: 24.04.2019
Хабаровск
Сообщений: 1,875


Не спец по Gdi+ и бейсику, но когда-то писал простые программы WinApi на пурсике, что-то еще смутно помню .
Цитата:
Сообщение от МишаИнженер Посмотреть сообщение
Есть ли возможность настроить ИЗОМЕТРИЧЕСКИЙ режим черчения на UserForm VBA?
SetMapMode прекрасно работает. Фокус в том, что GetDC при каждом вызове возвращает новый контекст, у которого режим сброшен в дефолтный MM_TEXT. Так что надо вызвать GetDC, сохранить результат в переменной, и передавать его как параметр во все остальные функции - SetMapMode, GetMapMode, DrawLine, DrawCircle, DrawRectangle, ReleaseDC. А сейчас при каждом их вызове контекст запрашивается заново, со сброшенным режимом.

Еще важно: WinApi не освобождает память самостоятельно, как VB. Всю очистку нужно делать вручную. Есть вызов CreateDC - нужен и DeleteDC; есть GetDC - нужен ReleaseDC, и т.д. для всех остальных объектов - окон, перьев и т.п.; в справке по функциям WinApi всегда в примечаниях указывают соответствующую функцию очистки. Количество создающих функций должно точно соответствовать количеству удаляющих, иначе в программе начнет течь память; иногда даже Windows можно заглючить своими действиями. Сейчас в программе функция hdc(), которая запрашивает контекст, вызывается много раз, а освобождающая ReleaseDC - редко.
Цитата:
Сообщение от МишаИнженер Посмотреть сообщение
А в какой контейнер записывается эта линия?
Очевидно, форма держит в памяти картинку со всеми начерченными линиями, и показывает ее на экране, когда надо. В чистом WinApi такой халявы нет, там обязательно в ответ на событие WM_PAINT нужно рисовать все, что должно быть видно в окне, иначе вместо картинки будут видны обрывки чужих окон.
Цитата:
Сообщение от МишаИнженер Посмотреть сообщение
надо показывать ДИНАМИЧЕСКУЮ отрисовку линии
Придется очищать форму и рисовать по ней заново - сначала все старые линии, потом новую. Известно, что скорость рисования через функции WinApi невысокая, от этого при рисовании экран будет сильно мигать. И есть стандартный трюк с двойной буферизацией, чтобы это мигание убрать. WinApi поддерживает этот трюк через специальные функции:
  1. Создаем копию контекста в памяти - CreateCompatibleDC
  2. Создаем картинку, которая имитирует поверхность окна - CreateCompatibleBitmap. Это картинка и есть буфер.
  3. Загружаем картинку в новый контекст - SelectObject
  4. Заливаем картинку цветом - FillRect
  5. Рисуем что надо - DrawLine и т.п. Рисуем не в контексте окна, а в новом. При этом все нарисованное пишется в буферную картинку.
  6. Когда картинка готова - выводим ее на форму, копируя контекст памяти в контекст формы - BitBlt

Код:
[Выделить все]
 
void OnPaint(HWND hWnd, WPARAM, LPARAM)
{
   PAINTSTRUCT ps;
   HDC hdc = BeginPaint(hWnd, &ps);
   
   HDC hMemDC = CreateCompatibleDC(hdc);  // Чистый контекст памяти

   RECT rect;
   GetWindowRect(hWnd, &rect);
   
   HBITMAP hbm = CreateCompatibleBitmap(  // Содержимое контекста
      hdc,
      rect.right - rect.left,
      rect.bottom - rect.top
   );
   SelectObject(hMemDC, hbm);             //Вставка содержимого в контекст

   
   RECT r = rect;
   r.left -= rect.left;
   r.right -= rect.left;
   r.top -= rect.top;
   r.bottom -= rect.top;
   
   FillRect(hMemDC, &r, GetStockObject(WHITE_BRUSH)); // Заливка контекста
   
   Rotate();
  
   for(UINT i=0; i<nNumOfElements; i++){              // Рисование в контексте
      MoveToEx(
         hMemDC,
         X + pRotatePoints[pElements[i].first].x,
         Y + pRotatePoints[pElements[i].first].y,
         0
      );
      LineTo(
         hMemDC,
         X + pRotatePoints[pElements[i].second].x,
         Y + pRotatePoints[pElements[i].second].y
      );
   }

   BitBlt(                          // Быстрый вывод из памяти на экран
      hdc,
      0,
      0,
      rect.right - rect.left,
      rect.bottom - rect.top,
      hMemDC,
      0,
      0,
      SRCCOPY
   );
   
   DeleteDC(hMemDC);  // Порядок уничтожения важен
   DeleteObject(hbm);   // Порядок уничтожения важен
   
   EndPaint(hWnd, &ps);
}
При рисовании новой линии, видимо, в картинке будут храниться старые линии, а после BitBlt в окне можно дорисовывать новую. А когда пользователь ткнет окончательное положение - записать новую линиию в картинку. И так далее по кругу.

Кстати, есть еще фунция CreateDIBSection - она создает картинку поверх массива байтов. В чистом C можно этот массив редактировать впрямую, тем самым рисуя на картинке попиксельно, скорость по сравнению с Gdi получается на порядки выше. Не знаю, можно ли этот трюк провернуть в VB.
Цитата:
Черчение не из той точки
Функция LineTo хитро устроена - она чертит из предыдущего положения, поэтому у нее не 4 координаты в параметрах, а только 2. Начальную точку надо задавать отдельно через MoveTo.
Нубий-IV вне форума  
 
Непрочитано 19.02.2023, 11:33
#11
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,052


Цитата:
Сообщение от Нубий-IV Посмотреть сообщение
Известно, что скорость рисования через функции WinApi невысокая, от этого при рисовании экран будет сильно мигать.
это было актуально лет так *-цать назад. Сейчас неизвестно, что больше будет тормозить - API GDI или сам VBA) Да и перерисовывать надо не всю форму, а лишь рабочий холст. Что опять же в VBA потребует приделывания очередных костылей. Слезать с VBA, в общем, надо) В приложении пример рисовалки на .Net Winforms (поставить вершину - левая кнопка мыши, завершить рисование - правая, Ctrl+Z тоже прикручена) - и без оптимизации "движка" не лагает заметно. Все сделано стандартными средствами ЯП.
Вложения
Тип файла: zip DrawLineWindowsForms.zip (16.9 Кб, 25 просмотров)
Сергей812 вне форума  
 
Непрочитано 19.02.2023, 12:30
#12
Нубий-IV

Инженер-философ
 
Регистрация: 24.04.2019
Хабаровск
Сообщений: 1,875


Цитата:
Сообщение от Сергей812 Посмотреть сообщение
это было актуально лет так *-цать назад.
Посмотрел - мои старые тестовые программки работают как и в стародавние времена: небуферизованный вывод мигает, буферизованный не мигает, доступ к массиву пикселей дает гладкий попиксельный рендер в реальном времени. Но у меня тесты посложенее были, там проволочные объекты крутились, и перерисовывать надо было все линии в новом положении, а не только последний сегмент. Так в небуферизованной версии вся картика мигает, как тут в Net-примере мигает последний сегмент.
Цитата:
Сообщение от Сергей812 Посмотреть сообщение
Все сделано стандартными средствами ЯП.
А как там перерисовка последнего сегмента сделана? Как он исчезает из предыдущего положения и появляется в новом, восстанавливая ранее закрашенную часть картинки?
Нубий-IV вне форума  
 
Непрочитано 19.02.2023, 12:39
1 | #13
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,052


Цитата:
Сообщение от Нубий-IV Посмотреть сообщение
А как там перерисовка последнего сегмента сделана? Как он исчезает из предыдущего положения и появляется в новом, восстанавливая ранее закрашенную часть картинки?
раньше написал же
Цитата:
Сообщение от Сергей812 Посмотреть сообщение
без оптимизации "движка"
т.е. просто заново перерисовываются все линии на холсте (PicturesBox). А последний сегмент дорисовывается - если стоит флаг рисования линии и курсор мыши находится над холстом: тогда от последней фиксированной точки до позиции мыши. А чуть "лагает" - просто гистерезис сделан на пару координатных единиц смещения мыши, чтобы перерисовку по каждому чиху не дергало.

----- добавлено через ~15 мин. -----
собственно весь код, где:

WorkCanvas - PicturesBox ака холст
OutDrawCoor - метка вывода координат мыши
SelectPenColorCBox - комбобокс цвета линии
SelectPenWidthCBox - комбобокс толщины линии
DrawLineBtn - кнопка рисования линии
ClearWorkCanvasBtn - кнопка очистки холста

Код:
[Выделить все]
 
using System.Collections.Generic;
using System.Drawing;


namespace DrawLineWindowsForms
{
    internal sealed class DrawLineInfo
    {
        private readonly Color _PenColor;

        private readonly float _PenWidth;

        private readonly List<Point> _Vertexes = new List<Point>();

        public DrawLineInfo(Color aPenColor, float aPenWidth)
        {
           _PenColor = aPenColor;
           _PenWidth = aPenWidth;
        }

        public void AddVertex(Point aPoint)
        {
            _Vertexes.Add(aPoint);
        }

        public bool RemoveLastVertex()
        {
            bool lRes = _Vertexes.Count > 0;
            if (_Vertexes.Count > 0) _Vertexes.RemoveAt(_Vertexes.Count - 1);
            return lRes;
        }

        public void Update(Graphics aGraphics)
        {
            if (_Vertexes.Count > 1)
            {
                float lScaleX = aGraphics.DpiX / 25.4F;
                float lScaleY = aGraphics.DpiY / 25.4F;
                Point[] lCVertexes = new Point[_Vertexes.Count];
                int i = 0;
                foreach (Point lVertex in _Vertexes)
                {
                    lCVertexes[i++] = new Point(
                        (int)(lVertex.X / lScaleX), (int)(lVertex.Y / lScaleY));
                }
                Pen lPen = new Pen(_PenColor, _PenWidth);
                aGraphics.DrawLines(lPen, lCVertexes);
            }
        }

        public void Update(Graphics aGraphics, Point aMouseLocation)
        {
            if (_Vertexes.Count > 0)
            {
                float lScaleX = aGraphics.DpiX / 25.4F;
                float lScaleY = aGraphics.DpiY / 25.4F;
                Point[] lCVertexes = new Point[_Vertexes.Count + 1];
                int i = 0;
                foreach (Point lVertex in _Vertexes)
                {
                    lCVertexes[i++] = new Point(
                        (int)(lVertex.X / lScaleX), (int)(lVertex.Y / lScaleY));
                }
                lCVertexes[i] = new Point((int)(aMouseLocation.X / lScaleX), 
                    (int)(aMouseLocation.Y / lScaleY));
                Pen lPen = new Pen(_PenColor, _PenWidth);
                aGraphics.DrawLines(lPen, lCVertexes);
            }
        }
    }

}

***************************************************************************************


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace DrawLineWindowsForms
{
    public partial class SuperPaint : Form
    {
        private const int cToleranceDispPosMouse = 2;

        private struct PenColorInfo
        {
            public string Desc;

            public Color Color;

            public PenColorInfo(string aDesc, Color aColor)
            {
                Desc = aDesc;
                Color = aColor;
            }
        }
        
		
        private struct PenWidthInfo
        {
            public string Desc;

            public float Width;

            public PenWidthInfo(string aDesc, float aWidth)
            {
                Desc = aDesc;
                Width = aWidth;
            }
        }


        private bool _StateDrawLine = false;

        private readonly List<DrawLineInfo> _DrawLines = new List<DrawLineInfo>();

        private readonly List<PenColorInfo> _PresetsPenColors = new List<PenColorInfo>();

        private readonly List<PenWidthInfo> _PresetsPenWidths = new List<PenWidthInfo>();

        private Point _LastPosMouseInWorkCanvas = new Point(0, 0);

        private bool _IsChangedPosMouseInWorkCanvas = false;


        private void UpdateEnabledStateControls()
        {
            SelectPenColorCBox.Enabled = !_StateDrawLine;
            SelectPenWidthCBox.Enabled = !_StateDrawLine;
            DrawLineBtn.Enabled = !_StateDrawLine;
        }


        private void FillSelectPenColorCBox()
        {
            _PresetsPenColors.Add(new PenColorInfo("Синий цвет", Color.Blue));
            _PresetsPenColors.Add(new PenColorInfo("Красный цвет", Color.Red));
            _PresetsPenColors.Add(new PenColorInfo("Зеленый цвет", Color.Green));
            foreach (PenColorInfo lPCI in _PresetsPenColors)
                SelectPenColorCBox.Items.Add(lPCI.Desc);
            if(_PresetsPenColors.Count > 0) SelectPenColorCBox.SelectedIndex = 0;
        }


        private void FillSelectPenWidthCBox()
        {
            _PresetsPenWidths.Add(new PenWidthInfo("0.25 мм", 0.25F));
            _PresetsPenWidths.Add(new PenWidthInfo("0.5 мм", 0.5F));
            _PresetsPenWidths.Add(new PenWidthInfo("1.0 мм", 1F));
            _PresetsPenWidths.Add(new PenWidthInfo("2.0 мм", 2F));
            _PresetsPenWidths.Add(new PenWidthInfo("3.0 мм", 3F));
            _PresetsPenWidths.Add(new PenWidthInfo("4.0 мм", 4F));
            _PresetsPenWidths.Add(new PenWidthInfo("5.0 мм", 5F));
            foreach (PenWidthInfo lPWI in _PresetsPenWidths)
                SelectPenWidthCBox.Items.Add(lPWI.Desc);
            if (_PresetsPenWidths.Count > 0) SelectPenWidthCBox.SelectedIndex = 0;
        }


        public SuperPaint()
        {
            InitializeComponent();
            FillSelectPenColorCBox();
            FillSelectPenWidthCBox();
            this.KeyPreview = true;
            this.KeyDown += new KeyEventHandler(SuperPaint_KeyDown); 
        }


        private void SuperPaint_Load(object sender, EventArgs e)
        {
            WorkCanvas.Paint += new PaintEventHandler(this.WorkCanvas_Paint);
        }

        private void SuperPaint_KeyDown(object sender, KeyEventArgs e)
        {
            if ((e.KeyValue == (int)Keys.Z) && e.Control && _StateDrawLine)
            {
                if (_DrawLines.Last().RemoveLastVertex())
                {
                    _IsChangedPosMouseInWorkCanvas = true;
                    WorkCanvas.Invalidate();
                }
            }
        }


        private void WorkCanvas_Paint(object sender, PaintEventArgs e)
        {
            Graphics lGraphics = e.Graphics;
            lGraphics.PageUnit = GraphicsUnit.Millimeter;
            lGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            if (_DrawLines.Count > 0)
            {
                if (_StateDrawLine)
                {
                    if (_IsChangedPosMouseInWorkCanvas)
                    {
                        if (_DrawLines.Count > 1)
                        {
                            for (int i = 0; i < (_DrawLines.Count - 1); i++)
                            {
                                _DrawLines[i].Update(lGraphics);
                            }
                            _DrawLines.Last().Update(lGraphics, _LastPosMouseInWorkCanvas);
                        }
                        else
                        {
                            _DrawLines.Last().Update(lGraphics, _LastPosMouseInWorkCanvas);
                        }
                        _IsChangedPosMouseInWorkCanvas = false;
                    }
                    else
                    {
                        _DrawLines.ForEach(delegate (DrawLineInfo aItem) { aItem.Update(lGraphics); });
                    }
                }
                else
                {
                    _DrawLines.ForEach(delegate (DrawLineInfo aItem) { aItem.Update(lGraphics); });
                }
            }
        }


        private void WorkCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            OutDrawCoor.Text = $"X = {e.X}; Y = {e.Y}";
            if ((Math.Abs(e.X - _LastPosMouseInWorkCanvas.X) > cToleranceDispPosMouse) ||
                (Math.Abs(e.Y - _LastPosMouseInWorkCanvas.Y) > cToleranceDispPosMouse))
            {
                _LastPosMouseInWorkCanvas = e.Location;
                _IsChangedPosMouseInWorkCanvas = true;
                WorkCanvas.Invalidate();
            }
            else _IsChangedPosMouseInWorkCanvas = false;
        }


        private void WorkCanvas_MouseLeave(object sender, EventArgs e)
        {
            OutDrawCoor.Text = null;
            _IsChangedPosMouseInWorkCanvas = false;
            if (_StateDrawLine) WorkCanvas.Invalidate();
        }


        private void DrawLineBtn_Click(object sender, EventArgs e)
        {
            _DrawLines.Add(new DrawLineInfo(
                _PresetsPenColors[SelectPenColorCBox.SelectedIndex].Color, 
                    _PresetsPenWidths[SelectPenWidthCBox.SelectedIndex].Width));
            _StateDrawLine = true;
            UpdateEnabledStateControls();
            WorkCanvas.Invalidate();
        }

        
        private void ClearWorkCanvasBtn_Click(object sender, EventArgs e)
        {
            _DrawLines.Clear();
            _StateDrawLine = false;
            UpdateEnabledStateControls();
            WorkCanvas.Invalidate();
        }


        private void WorkCanvas_MouseDown(object sender, MouseEventArgs e)
        {
            if ((e.Button == MouseButtons.Left) && _StateDrawLine)
            {
                _DrawLines.Last().AddVertex(e.Location);
                WorkCanvas.Invalidate();
            }
            if ((e.Button == MouseButtons.Right) && _StateDrawLine)
            {
                _StateDrawLine = false;
                UpdateEnabledStateControls();
            }
        }
    }

}

Последний раз редактировалось Сергей812, 19.02.2023 в 12:54.
Сергей812 вне форума  
 
Непрочитано 19.02.2023, 13:19
#14
Нубий-IV

Инженер-философ
 
Регистрация: 24.04.2019
Хабаровск
Сообщений: 1,875


Цитата:
Сообщение от Сергей812 Посмотреть сообщение
т.е. просто заново перерисовываются все линии на холсте (PicturesBox)
Все остальные линии не мигают. Мигает только последний сегмент. "Мигает" - значит, что иногда видно, как этой линии еще нет, вместо нее только серый фон, а потом она уже есть.

Когда в WinApi обрабатывается перерисовка, приходится сначала заливать форму фоном, а потом рисовать поверх линии - вот в этот момент и происходит моргание: форма то чисто белая, то на ней уже линии. А буферизация просто выводит новую картинку поверх старой, и мигания не видно, потому что оно на скрытой буферной картинке происходит, и видно только как старая картинка просто мгновенно заменяется новой.

А тут все выглядит так, будто старые линии остаются как были, а перерисовывается только последняя, потому и мигает. То есть выглядит так, как будто тут уже есть оптимизация - оптимизированы старые линии. Вот и итересно, почему не мигают старые линии? Должны или мигать все, или не мигать никто.

На словах тяжело объяснить. Разницу "мигает - не мигает " лучше видно на моих примерах, во вложении:

Пара кубиков. В меню в параметрах на современном железе надо число сторон поставить побольше, штук 20. Вращать клавишами-стрелками, или полосами прокрутки.
1. Кубик без буферизации.
2. Кубик с буферизацией.

3. Простейший калейдоскоп - загрузить картинку и двигать область в левом окне. Подсказки в заголовке, настройки в меню.

А в NET - примере старые линии рисуются, как у меня кубик версии 2, а последний сегмент - как кубик версии 1. В чем фокус?!
Вложения
Тип файла: rar GdiTest.rar (1.40 Мб, 25 просмотров)
Нубий-IV вне форума  
 
Непрочитано 19.02.2023, 13:55
#15
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,052


Цитата:
Сообщение от Нубий-IV Посмотреть сообщение
А в NET - примере старые линии рисуются, как у меня кубик версии 2, а последний сегмент - как кубик версии 1. В чем фокус?!
а сейчас как?
Вложения
Тип файла: zip DrawLineWindowsForms2.zip (16.9 Кб, 25 просмотров)
Сергей812 вне форума  
 
Непрочитано 19.02.2023, 14:07
#16
Нубий-IV

Инженер-философ
 
Регистрация: 24.04.2019
Хабаровск
Сообщений: 1,875


Цитата:
Сообщение от Сергей812 Посмотреть сообщение
а сейчас как?
А сейчас все как надо. Никто не мигает - ни старые линии, ни новые.

Кстати, гугель подсказывает, что в Net - формах из коробки поддерживается двойная буферизация. Не могу вспомнить, в старом VB (не VBA) было ли свойство DoubleBuffered у форм, или я его только где-то в Net видел?
Нубий-IV вне форума  
 
Непрочитано 19.02.2023, 14:14
#17
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,052


Цитата:
Сообщение от Сергей812 Посмотреть сообщение
А чуть "лагает" - просто гистерезис сделан на пару координатных единиц смещения мыши, чтобы перерисовку по каждому чиху не дергало.
просто в коде заменил private const int cToleranceDispPosMouse = 2 на нулевое значение, т.е. убрал гистерезис. А в вашем примере небыстро, конечно - наверно, не имеет смысла соревноваться с разработчиками FrameWork в быстродействии, у них явно есть больший доступ к информации по коду GDI)

----- добавлено через ~5 мин. -----
если есть сильное желание копнуть "вглубь" - исходной код того же класса Graphics, через который в моем примере проводится отрисовка линий.

Последний раз редактировалось Сергей812, 19.02.2023 в 14:21.
Сергей812 вне форума  
 
Непрочитано 19.02.2023, 14:46
#18
Нубий-IV

Инженер-философ
 
Регистрация: 24.04.2019
Хабаровск
Сообщений: 1,875


Цитата:
Сообщение от Сергей812 Посмотреть сообщение
в вашем примере небыстро
В моих примерах нет проблем с быстродействием, есть проблемы с мерцанием в версии без буферизации. В первой версии мерцание есть даже в маленьком кубике, даже при одиночных нажатиях клавиш. А во второй - нет даже в больших кубиках, у которых явно тормозит прорисовка.

В NET форме есть свойство DoubleBuffered? Его можно выставить в False? Если от этого начнется мерцание, значит, NET просто автоматически делает то, что мне приходилось делать вручную. И тогда в VB тоже придется делать вручную, потому что у него нет такой фишки.
Нубий-IV вне форума  
 
Непрочитано 19.02.2023, 14:58
#19
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,052


Цитата:
Сообщение от Нубий-IV Посмотреть сообщение
В NET форме есть свойство DoubleBuffered? Его можно выставить в False?
есть, но оно и стоит в false по умолчанию.
Сергей812 вне форума  
 
Непрочитано 19.02.2023, 15:12
1 | #20
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,052


вариант с включенным DoubleBuffered
Вложения
Тип файла: zip DrawLineWindowsForms3.zip (16.9 Кб, 23 просмотров)
Сергей812 вне форума  
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > Почему не удается подключить GDIplus.dll к VBA?

Размещение рекламы


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
не удается подключить "автоматическое фланцевое соединение"( AutoCAD Plant 3D 2019)? Q_qq Вертикальные решения на базе AutoCAD 1 24.09.2021 16:59
Почему выдает ошибку "не удается найти обозначение детали" из миникаталога ?AutoCAD Plant 3D2019 Q_qq Вертикальные решения на базе AutoCAD 4 24.09.2021 16:42
Можно ли подключить бытовые сантехнические приборы к К3? Viarina Водоснабжение и водоотведение 5 16.10.2014 09:22
Почему при расчёте в Robote простой схемы эпюра My получается неправильной? МишаИнженер Robot 13 02.03.2010 12:26
Почему двутавр 90Б1 высота 893мм ? dextron3 Разное 33 11.03.2009 23:31