1

Тема: AHK: графика

Есть необходимость построить прямо в окне AutoHotkey GUI простейшие графические изображения (линии, точки, окружности), не запуская сторонних программ.
Вопрос в том, как это лучше сделать. Имеется вариант размещать в окне элементы управления типа "Picture" (с ссылкой на изображение размером 1х1 пиксель).

2

Re: AHK: графика

Можно ещё и с буквами. big_smile

#SingleInstance, Force

Gui, Font, s1, Lucida console

a := 00
b := 100
Loop, 100
{
a := a+2
b := 31.4*sin(a)+100
GUI, Add, text, x%a% y%b%,o
}
GUI, Show, h200 w200

F12:: Exitapp

3

Re: AHK: графика

А использование Canvas и SetPixel не подходит ?

http://www.autohotkey.com/forum/topic7938.html

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

4

Re: AHK: графика

GDI+, там и примеры есть.
Если скажешь, что нужно конкретно, могу пояснить.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

5

Re: AHK: графика

Спасибо за ссылки, сейчас буду читать.
Вот пока наваял ("навалял" smile ).

#SingleInstance, Force
pi := 3.1415926535
Gui, Font, s1, Lucida console

 fr := 20    ; Качество изображения (от 10 до 50)
  w := 100    ; Ширина одного периода (в пикселях)
amp := 50    ; Амплитуда (в пикселях)
  n := 2    ; Число периодов

 x0 := 0    ; Начальные
 y0 := 100    ; координаты

a := 0
Loop, % fr*(n*2*pi)
{
b  := -amp*sin(a)+y0
a1 := a*w/(2*pi) + x0

a  := a + 1/fr
GUI, Add, text, x%a1% y%b%, | ; рисовать буквами
;Gui, Add, Picture, x%a1% y%b%, 1.bmp ; рисовать картинками
; GUI, Add, text, x%a1% y100, o ; изобразить горизонтальную ось
}
GUI, Show, h200 w300, Test - построение синусоиды

F12:: Exitapp

6

Re: AHK: графика

Xameleon пишет:

А использование Canvas и SetPixel не подходит ?
http://www.autohotkey.com/forum/topic7938.html

Как-то медленно прорисовывает. Зато при перетаскивании окна не требует перерисовки и можно цвета менять:

#SingleInstance, Force
pi := 3.1415926535
Gui, Font, s1, Lucida console

 fr := 20    ; Качество изображения (от 10 до 50)
  w := 100    ; Ширина одного периода (в пикселях)
amp := 50    ; Амплитуда (в пикселях)
  n := 2    ; Число периодов

 x0 := 0    ; Начальные
 y0 := 100    ; координаты

Gui, Show, w200 h300, gui1: unique title

SelectCanvas( "gui1: unique title" )


a := 0
Loop, % fr*(n*2*pi)
{
b  := ceil(-amp*sin(a)+y0)
a1 := ceil(a*w/(2*pi) + x0)

a  := a + 1/fr
SetPixel( a1, b, 1, "red" ) ; рисовать при помощи Canvas
SetPixel( a1, y0, 1, "blue" ) ; изобразить горизонтальную ось
}

return





GuiClose:
ExitApp


SelectCanvas( p_title=false )
{
   static   hw_canvas

   if ( !p_title )
      return, hw_canvas
   
   Process, Exist
   WinGet, hw_canvas, ID, %p_title% ahk_class AutoHotkeyGUI ahk_pid %ErrorLevel%
}

SetPixel( p_x, p_y, p_size, p_color )
{
   static   total
   
   total++

   Gui, Add, Progress, % "x" ( p_x-1 ) " y" ( p_y-1 ) " w" ( p_size+2 ) " h" ( p_size+2 ) " background" p_color
   
   hw_canvas := SelectCanvas()

   ; WS_EX_STATICEDGE   
   Control, ExStyle, -0x20000, msctls_progress32%total%, ahk_id %hw_canvas%
   
   WinSet, Redraw,, ahk_id %hw_canvas%
}

7

Re: AHK: графика

teadrinker, в любом примере из GDI+ получаю ошибку:

AutoHotkey.exe пишет:

Error: Call to nonexistent function.

Specifically: Gdip_Startup()

Line#
008: SetBatchLines,-1
---> 014: if !pToken := Gdip_Startup()

Чего в супе не хватает? Форточки ХР, библиотеку не скачивал.

8

Re: AHK: графика

Gdip.ahk должна лежать в пользовательской библиотеке (сам не знаю где это)
Или положить рядом с запускаемым скриптом и раскомментировать строку

;#Include, Gdip.ahk

9

Re: AHK: графика

Пользовательская и стандартная библиотеки. (ё-моё, пора бы знать wink)

Синусоида будет как-то так:

   If !pToken := Gdip_Startup()
   {
      MsgBox, 48, Ошибка GDI+, Убедитесь в наличии gdiplus.dll в вашей системе!
      ExitApp
   }
   SetWinDelay, 0
   SetBatchLines, -1
   
   k1 = 25   ; коэффициент ширины периода
   k2 = 70   ; коэффициент высоты периода
   Width := 400
   Height := 200   ; размеры картинки
   H2 := Height//2, W2 := Width//2   ; средние пиксели
   
   Gui, Add, Pic, x20 y20 w%Width% h%Height% hwndhPic +0xE      ; SS_BITMAP = 0xE
   
   pBitmap := Gdip_CreateBitmap(Width, Height)
   G := Gdip_GraphicsFromImage(pBitmap)
   Gdip_SetSmoothingMode(G, 4)
   pBrush := Gdip_BrushCreateSolid(0xffffffff)   ; кисть для заливки
   pBlackPen := Gdip_CreatePen(0xff000000, 1)    ; карандаш для осей
   pBluePen := Gdip_CreatePen(0xff0000ff, 1)     ; карандаш для графика
   
   Gdip_FillRectangle(G, pBrush, -1, -1, Width+2, Height+2)
   Gdip_DrawLine(G, pBlackPen, 0, H2, Width, H2)
   Gdip_DrawLine(G, pBlackPen, W2, 0, W2, Height)
   
   x1 = 0
   y1 := Round((-Sin((x1 - W2)/k1))*k2 + H2)
   While x1 < Width
   {
      x2 := x1 + 1
      y2 := Round((-Sin((x2 - W2)/k1))*k2 + H2)
      Gdip_DrawLine(G, pBluePen, x1, y1, x2, y2)
      x1 := x2, y1 := y2
   }
   
   hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
   SetImage(hPic, hBitmap)
   
   Gdip_DeleteBrush(pBrush), Gdip_DeletePen(pBlackPen), Gdip_DeletePen(pBluePen)
   Gdip_DisposeImage(pBitmap), DeleteObject(hBitmap), Gdip_DeleteGraphics(G)
   Gdip_Shutdown(pToken)
   
   Gui, Show, % "w" Width+40 " h" Height + 40
   Return
   
GuiClose:
   ExitApp
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

10

Re: AHK: графика

teadrinker пишет:

Пользовательская и стандартная библиотеки. (ё-моё, пора бы знать wink)

Спасибо, закинул GDIp.ahk в Мои документы\AutoHotkey\Lib - заработало.

teadrinker пишет:

Синусоида будет как-то так:

Можно добавить комментариев?

11

Re: AHK: графика

   If !pToken := Gdip_Startup()
   {
      MsgBox, 48, Ошибка GDI+, Убедитесь в наличии gdiplus.dll в вашей системе!
      ExitApp
   }
   SetWinDelay, 0
   SetBatchLines, -1
   
   k1 = 28   ; коэффициент частоты
   k2 = 80   ; коэффициент амплитуды
   Width := 440
   Height := 200   ; размеры картинки
   H2 := Height//2, W2 := Width//2   ; средние пиксели
   
   Gui, Color, 0xD4D0C8
   Gui, Add, Pic, x20 y20 w%Width% h%Height% hwndhPic +0xE      ; SS_BITMAP = 0xE
   
; создаём битовую карту нужных размеров и получаем указатель (поинтер) на неё:
   pBitmap := Gdip_CreateBitmap(Width, Height)
   
; создаём объект Graphics и получаем указатель на него:
   G := Gdip_GraphicsFromImage(pBitmap)
   
   Gdip_SetSmoothingMode(G, 4)    ; вариант сглаживания при рисовании (см. Gdip.ahk)
   pBrush := Gdip_BrushCreateSolid(0xffffffff)  ; кисть для заливки
   pBlackPen := Gdip_CreatePen(0x88000000, 1)   ; карандаш для осей
   pBluePen := Gdip_CreatePen(0xff0000ff, 1)    ; карандаш для графика
   
   Gdip_FillRectangle(G, pBrush, -1, -1, Width+2, Height+2)   ; заливаем прямоугольник с небольшим запасом
   
; рисуем оси графика:
   Gdip_DrawLine(G, pBlackPen, 0, H2, Width, H2)
   Gdip_DrawLine(G, pBlackPen, W2, 0, W2, Height)
   
; рисуем сам график:
   x1 = 0
   y1 := Round((-Sin((x1 - W2)/k1))*k2 + H2)
   While x1 < Width
   {
      x2 := x1 + 1
      y2 := Round((-Sin((x2 - W2)/k1))*k2 + H2)
      Gdip_DrawLine(G, pBluePen, x1, y1, x2, y2)
      x1 := x2, y1 := y2
   }
   
   hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)  ; хэндл объекта bitmap для использования в SetImage()
   SetImage(hPic, hBitmap)  ; применяем нашу битовую карту к контролу Picture со стилем SS_BITMAP
   
; удаляем ненужные объекты и освобождаем память:
   Gdip_DeleteBrush(pBrush), Gdip_DeletePen(pBlackPen), Gdip_DeletePen(pBluePen)
   Gdip_DisposeImage(pBitmap), DeleteObject(hBitmap), Gdip_DeleteGraphics(G)
   Gdip_Shutdown(pToken)
   
   Gui, Show, % "w" Width+40 " h" Height + 40
   Return
   
GuiClose:
   ExitApp
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

12

Re: AHK: графика

Можно оси сделать менее жирными, уменьшив прозрачность их карандаша (отредактировано).

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

13

Re: AHK: графика

Спасибо, начинаю понемногу разбираться. wink

14

Re: AHK: графика

Я собираюсь запускать скрипт на компьютере, на котором не установлена AutoHotkey. Если откомпилировать скрипт, он будет искать файл GDIp.ahk?

Вот, подогнал под свои нужды, рисует прямо на глазах (теперь думаю, как избавиться от мельканий и разгрузить процессор):

;--------= НАЧАЛЬНЫЕ ПРЕДУСТАНОВКИ =----------------------------------------------------------------------------
#SingleInstance, Force
 If !pToken := Gdip_Startup()
   {
      MsgBox, 48, Ошибка GDI+, Убедитесь в наличии gdiplus.dll в вашей системе!
      ExitApp
   }
   SetWinDelay, 0
   SetBatchLines, -1


;--------= НАСТРОЙКИ ПОЛЬЗОВАТЕЛЯ =----------------------------------------------------------------------------  
   k1 = 28   ; коэффициент частоты
   k2 = 80   ; коэффициент амплитуды
   Width := 440
   Height := 200   ; размеры картинки
   H2 := Height//2, W2 := Width//2   ; средние пиксели


;--------= ПОСТРОЕНИЕ ИЗОБРАЖЕНИЯ =----------------------------------------------------------------------------    
   Gui, Color, 0xD4D0C8        ; задаётся фон окна

; добавляется элемент Picture, являющийся основой растрового изображения
   Gui, Add, Pic, x20 y20 w%Width% h%Height% hwndhPic +0xE      ; SS_BITMAP = 0xE
   
; создаём битовую карту нужных размеров и получаем указатель (поинтер) на неё:
   pBitmap := Gdip_CreateBitmap(Width, Height)
   
; создаём объект Graphics и получаем указатель на него:
   G := Gdip_GraphicsFromImage(pBitmap)
   
   Gdip_SetSmoothingMode(G, 4)    ; вариант сглаживания при рисовании (см. Gdip.ahk)
   pBrush := Gdip_BrushCreateSolid(0xffffffff)  ; кисть для заливки
   pBlackPen := Gdip_CreatePen(0x88000000, 1)   ; карандаш для осей
   pBluePen := Gdip_CreatePen(0xff0000ff, 1)    ; карандаш для графика
   
   Gdip_FillRectangle(G, pBrush, -1, -1, Width+2, Height+2)   ; заливаем прямоугольник с небольшим запасом
   
; рисуем оси графика:
   Gdip_DrawLine(G, pBlackPen, 0, H2, Width, H2)
   Gdip_DrawLine(G, pBlackPen, W2, 0, W2, Height)
   
   Gui, Show, % "w" Width+40 " h" Height + 40 ;<<<<<

; рисуем сам график:
   x1 = 0
   y1 := Round((-Sin((x1 - W2)/k1))*k2 + H2)
   While x1 < Width
   {
    x2 := x1 + 1
    y2 := Round((-Sin((x2 - W2)/k1))*k2 + H2)
    Gdip_DrawLine(G, pBluePen, x1, y1, x2, y2)
    x1 := x2, y1 := y2
;; }
    hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)  ; хэндл объекта bitmap для использования в SetImage()
    SetImage(hPic, hBitmap)  ; применяем нашу битовую карту к контролу Picture со стилем SS_BITMAP
   }
   
; удаляем ненужные объекты и освобождаем память:
   Gdip_DeleteBrush(pBrush), Gdip_DeletePen(pBlackPen), Gdip_DeletePen(pBluePen)
   Gdip_DisposeImage(pBitmap), DeleteObject(hBitmap), Gdip_DeleteGraphics(G)
   Gdip_Shutdown(pToken)
   
;;  Gui, Show, % "w" Width+40 " h" Height + 40 ;<<<<<
   Return

Esc::   
GuiClose:
   ExitApp

15

Re: AHK: графика

ypppu пишет:

Я собираюсь запускать скрипт на компьютере, на котором не установлена AutoHotkey. Если откомпилировать скрипт, он будет искать файл GDIp.ahk?

Прочитай статью по моей ссылке до конца.

ypppu пишет:

теперь думаю, как избавиться от мельканий и разгрузить процессор

Если ты только сегодня познакомился с GDI+, вряд ли это получится у тебя в скором времени! wink Чтобы рисовать "на глазах", нужен совсем другой алгоритм отображения. Кроме того, в коде, что ты наваял, грубая ошибка: в цикле много раз подряд создаётся обект hBitmap (он каждый раз будет другим), а удаляется в конце только один раз. Такой скрипт будет бешено жрать память. Можешь открыть Диспетчер задач и проверить.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

16

Re: AHK: графика

teadrinker пишет:

Прочитай статью по моей ссылке до конца.

Libraries of Functions: Standard Library and User Library [v1.0.47+] Прочитал ещё раз, но не понял. Придётся выделить время, чтобы качественно перевести. Методом тыка и ошибок понял, что если GDIp.ahk находится в пользовательской или стандартной библиотеке (либо указан в теле скрипта через #Include), то скомпилированному скрипту этот файл уже не понадобится.

teadrinker пишет:

Если ты только сегодня познакомился с GDI+, вряд ли это получится у тебя в скором времени! wink Чтобы рисовать "на глазах", нужен совсем другой алгоритм отображения. Кроме того, в коде, что ты наваял, грубая ошибка: в цикле много раз подряд создаётся объект hBitmap (он каждый раз будет другим), а удаляется в конце только один раз. Такой скрипт будет бешено жрать память. Можешь открыть Диспетчер задач и проверить.

А в общих чертах, что это за алгоритм? Или может рисовать отдельными пикселями, не соединяя их отрезками, будет не так тяжко для CPU?

17

Re: AHK: графика

В общих чертах, для этого лучше использовать layered windows, что в примерах к Gdip.ahk. Они не мелькают при перерисовке.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

18

Re: AHK: графика

Спасибо, буду копать.

   о
  /|\_&#8215;
  / \       &#64481;&#64392;&#64468;&#64484;

19

Re: AHK: графика

Даже написал ради интереса:

   If !pToken := Gdip_Startup()
   {
      MsgBox, 48, Ошибка GDI+, Убедитесь в наличии gdiplus.dll в вашей системе!
      ExitApp
   }

   OnExit, Exit
   SetBatchLines, -1
   SetWinDelay, 0

   k1 = 52   ; коэффициент частоты
   k2 = 80   ; коэффициент амплитуды
   Width = 502
   Height = 250       ; размеры картинки
   SleepDuration = 6  ; пауза в цикле
   Frame = 10         ; рамка

   H2 := Height//2, W2 := Width//2
   X := (A_ScreenWidth-Width)//2
   Y := (A_ScreenHeight-Height)//2

   Gui, -Caption +E0x80000 +LastFound +ToolWindow +AlwaysOnTop  ; WS_EX_LAYERED := 0x80000
   WinGet, ID
   Gui, Show
   OnMessage(0x201, "WM_LBUTTONDOWN")
   OnMessage(0x003, "WM_MOVE")

   DllCall("Winmm\timeBeginPeriod", UInt, 3)

   hbm := CreateDIBSection(Width, Height)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)
   Gdip_SetSmoothingMode(G, 4)

   pFillBrush := Gdip_BrushCreateSolid(0xffffffff)   ; кисть для заливки
   pFrameBrush := Gdip_BrushCreateSolid(0xffD4D0C8)  ; кисть для рамки
   pGrayPen := Gdip_CreatePen(0xff808080, 1)         ; карандаш для оси
   pBluePen := Gdip_CreatePen(0xff0000ff, 1)         ; карандаш для графика

   Gdip_FillRectangle(G, pFrameBrush, 0, 0, Width, Height)
   Gdip_FillRectangle(G, pFillBrush, Frame, Frame, Width-Frame*2, Height-Frame*2)
   Gdip_DeleteBrush(pFrameBrush)

   Gdip_DrawLine(G, pGrayPen, Frame, H2, Width-Frame, H2)
   UpdateLayeredWindow(ID, hdc, X, Y, Width, Height)
   Sleep, 500

   Loop
   {
      i := !i
      x1 := Frame
      y1 := Round((-Sin((x1 - W2)*k1/1000))*k2 + H2)
      While x1 < Width-Frame
      {
         x2 := x1 + 1
         y2 := Round((-Sin((x2 - W2)*k1/1000))*k2 + H2)
         if i
            Gdip_DrawLine(G, pBluePen, x1, y1, x2, y2)
         Else
         {
            end := x1 = Width-Frame-1
            Gdip_FillRectangle(G, pFillBrush, x1, Frame+1, end ? 1 : 2, Height-Frame*2-2)
            Gdip_DrawLine(G, pGrayPen, x1, H2, x2 + (end ? 0 : 1), H2)
         }
         x1 := x2, y1 := y2
         UpdateLayeredWindow(ID, hdc, X > A_ScreenWidth ? 0 : X, Y, Width, Height)
         DllCall("Sleep", UInt, SleepDuration)
      }
   }

GuiClose:
GuiEscape:
   ExitApp

Exit:
   Gdip_DeletePen(pGrayPen), Gdip_DeletePen(pBluePen), Gdip_DeleteBrush(pFillBrush)
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc), Gdip_DeleteGraphics(G)
   Gdip_Shutdown(pToken)
   DllCall("Winmm\timeEndPeriod", UInt, 3)
   ExitApp

WM_LBUTTONDOWN()
{
   PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_MOVE(wp, lp)
{
   global X, Y
   X := lp & 0xFFFF, Y := lp >> 16
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

20

Re: AHK: графика

Правильно ли я понял, что после задания окну GUI стиля WS_EX_LAYERED := 0x80000 использовать в нём элементы вроде "Edit", "Button", "Progress" и т. п. нельзя? Если требуется ввести исходные данные, нужно создавать ещё одно окно GUI?

21

Re: AHK: графика

Нельзя после использования функции UpdateLayeredWindow(). Рисовать можно и в обычных окнах, но там алгоритм сложнее.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

22

Re: AHK: графика

teadrinker, расшифруй, пожалуйста, блок:

 Else
  {
  end := x1 = Width-Frame-1
  Gdip_FillRectangle(G, pFillBrush, x1, Frame+1, end ? 1 : 2, Height-Frame*2-2) ; Не понял, что делает эта строчка
  Gdip_DrawLine(G, pGrayPen, x1, H2, x2 + (end ? 0 : 1), H2)
  }

23

Re: AHK: графика

Здесь я постепенно "стираю" нарисованный график путём последовательной зарисовки его белыми прямоугольниками высотой, чуть меньшей высоты белого поля, и шириной в 2 пиксела, за исключением момента, когда до конца поля остаётся всего один пиксел, тогда ширина прямоугольника уменьшается до 1 пиксела, чтобы не закрасить часть серой рамки. Параллельно перерисовывается ось, которая тоже закрашивается белыми прямоугольниками.
В начале я попробовал стирать график путем закрашивания его белым по тому же алгоритму, что он был нарисован, но так не почему-то не получилось, он не стирался полностью, оставался след.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

24

Re: AHK: графика

Понятно. Изменил Gdip_SetSmoothingMode(G, 1), заработало нормально закрашивание карандашом.
Изменил While x1 < Width-Frame-1, чтобы не упиралось в рамку.

25

Re: AHK: графика

ypppu пишет:

Изменил Gdip_SetSmoothingMode(G, 1)

Я тоже подумал, что связано с этим, но если не применять сглаживание, рисуется некрасиво.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg