[GDI+] Wie bekomme ich DoubleBuffering ?

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

[GDI+] Wie bekomme ich DoubleBuffering ?

Beitrag von Mijikai »

Für ein kleines Grafik-Projekt wollte ich mit der GDI+ API arbeiten.
Leider flackert das Ganze :(

Es sollte jedoch möglich sein einen zusätzlichen Buffer (DoubleBuffering)
zu verwenden. :freak:

Leider weiß ich nicht wie das Umzusetzten ist und hab bisher nur Beispiele
mit GDI gefunden. :oops:

Wie würde das mit GDI+ aussehen ?

Hier mein flackernder Testcode:

Code: Alles auswählen

Import "gdiplus.lib"
  GdiplusStartup(*Token,*Input,*Output)
  GdiplusShutdown(*Token)
  GdipCreateFromHDC(HDC.i,*Graphics)
  GdipDeleteGraphics(*Graphics)
  GdipCreateSolidFill(Color.i,*Brush)
  GdipCreatePen1(Color.i,Width.f,Unit.i,*Pen)
  GdipDeletePen(*Pen)
  GdipDeleteBrush(*Brush)
  GdipFillRectangle(*Graphics,*Brush,X.f,Y.f,Width.f,Height.f)
  GdipDrawRectangle(*Graphics,*Pen,X.f,Y.f,Width.f,Height.f)
EndImport

Structure GdiplusStartupInput
  GdiplusVersion.i
  *DebugEventCallback
  SuppressBackgroundThread.i
  SuppressExternalCodecs.i
EndStructure

Enumeration
  #UnitWorld
  #UnitDisplay
  #UnitPixel
  #UnitPoint
  #UnitInch
  #UnitDocument
  #UnitMillimeter
EndEnumeration

Procedure.i WindowProc(Window.i,Message.i,wParam.i,lParam.i)
  Protected PS.PAINTSTRUCT
  Protected Graphics.i
  Protected Pen.i
  Protected PenRed.i
  Protected Brush.i
  Protected ii.i
  Static i.f = 50
  Select Message
    Case #WM_PAINT
      i + 0.5
      If i > 200
        i = 50
      EndIf
      ii = i
      BeginPaint_(Window,@PS)
      If GdipCreateFromHDC(PS\hdc,@Graphics) = #S_OK
        If GdipCreatePen1($FF0000000,2,#UnitPixel,@Pen) = #S_OK
          GdipCreatePen1(ii | $FFFF000F,i/10,#UnitPixel,@PenRed)
          GdipCreateSolidFill($FF000000,@Brush)
          GdipFillRectangle(Graphics,Brush,0,0,400,400)
          GdipDrawRectangle(Graphics,PenRed,50,50,i,i)
          GdipDeleteBrush(Brush)
          GdipDeletePen(Pen) 
        EndIf
        GdipDeleteGraphics(Graphics)
      EndIf
      EndPaint_(Window,@PS)
      InvalidateRect_(Window,#Null,#Null)
      Sleep_(1) 
      ProcedureReturn 0
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure 

Procedure.i Window()
  Protected Window.i
  Protected Event.i
  Protected GDI_Startup.GdiplusStartupInput
  Protected GDI_Token.i
  Window = OpenWindow(#PB_Any,#Null,#Null,400,400,"GDI-Test",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  If Window
    GDI_Startup\GdiplusVersion = 1
    GDI_Startup\SuppressExternalCodecs = #True
    If GdiplusStartup(@GDI_Token,@GDI_Startup,#Null) = #S_OK
      SetWindowCallback(@WindowProc()) 
      Repeat
        Event = WaitWindowEvent()
        Select Event
          Case #PB_Event_CloseWindow
            Break
        EndSelect
      ForEver
    EndIf
  EndIf
EndProcedure

Window()
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Re: [GDI+] Wie bekomme ich DoubleBuffering ?

Beitrag von Fluid Byte »

Bitte nicht WM_PAINT, das ist grausam. Ansonsten einfach einen Image-Buffer benutzen:

Code: Alles auswählen

EnableExplicit

Import "gdiplus.lib"
	GdiplusStartup(*Token,*Input,*Output)
	GdiplusShutdown(*Token)
	GdipCreateFromHDC(HDC.i,*Graphics)
	GdipDeleteGraphics(*Graphics)
	GdipCreateSolidFill(Color.i,*Brush)
	GdipCreatePen1(Color.i,Width.f,Unit.i,*Pen)
	GdipDeletePen(*Pen)
	GdipDeleteBrush(*Brush)
	GdipFillRectangle(*Graphics,*Brush,X.f,Y.f,Width.f,Height.f)
	GdipDrawRectangle(*Graphics,*Pen,X.f,Y.f,Width.f,Height.f)
EndImport

Structure GdiplusStartupInput
	GdiplusVersion.i
	*DebugEventCallback
	SuppressBackgroundThread.i
	SuppressExternalCodecs.i
EndStructure

Enumeration
	#UnitWorld
	#UnitDisplay
	#UnitPixel
	#UnitPoint
	#UnitInch
	#UnitDocument
	#UnitMillimeter
EndEnumeration

#WIDTH = 400
#HEIGHT = 400

Define GDI_Startup.GdiplusStartupInput
Define i.f, GDI_Token, hdc, Graphics, Pen, ii, PenRed, Brush

GDI_Startup\GdiplusVersion = 1
GDI_Startup\SuppressExternalCodecs = #True

If GdiplusStartup(@GDI_Token,@GDI_Startup,0) ! #S_OK
	MessageRequester("Error","Couldn't load GDI+ library",#PB_MessageRequester_Error) : End
EndIf

OpenWindow(0,0,0,#WIDTH,#HEIGHT,"GDI-Test",#PB_Window_ScreenCentered | #PB_Window_SystemMenu)

CreateImage(0,#WIDTH,#HEIGHT)

While WindowEvent() ! #PB_Event_CloseWindow	
	i + 0.5
	
	If i > 200 : i = 50 : EndIf
	
	hdc = StartDrawing(ImageOutput(0))
	If GdipCreateFromHDC(hdc,@Graphics) = #S_OK
	  If GdipCreatePen1($FF0000000,2,#UnitPixel,@Pen) = #S_OK
	    GdipCreatePen1(ii | $FFFF000F,i/10,#UnitPixel,@PenRed)
	    GdipCreateSolidFill($FF000000,@Brush)
	    GdipFillRectangle(Graphics,Brush,0,0,#WIDTH,#HEIGHT)
	    GdipDrawRectangle(Graphics,PenRed,50,50,i,i)
	    GdipDeleteBrush(Brush)
	    GdipDeletePen(Pen)
	  EndIf
	  GdipDeleteGraphics(Graphics)
	EndIf			
	StopDrawing()
		
	StartDrawing(WindowOutput(0))
	DrawImage(ImageID(0),0,0)
	StopDrawing()
	Delay(1)
Wend
Windows 10 Pro, 64-Bit / Outtakes | Derek
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: [GDI+] Wie bekomme ich DoubleBuffering ?

Beitrag von Mijikai »

Danke für die Antwort aber ich suche eine Lösung mit der GDI+ API...
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Re: [GDI+] Wie bekomme ich DoubleBuffering ?

Beitrag von Fluid Byte »

Jo, und die Lösung habe ich gepostet. Wo hakt es jetzt noch :?:
Windows 10 Pro, 64-Bit / Outtakes | Derek
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: [GDI+] Wie bekomme ich DoubleBuffering ?

Beitrag von ccode_new »

Hallo Mijikai,

Ähhmmm....

Wieso Windows-API mit GDI ?

Naja...

Ich glaube die Windows API Lösung wird ziemlich ähnlich der Lösung von "Fluid Byte".

Ob du nun irgend ein "HBITMAP mbmp = CreateBitmap(..)" oder ähnlich für den Buffer benutzt ist doch egal, oder ?

Irgend einen Puffer (Buffer) wirst du wohl benötigen. Das steckt ja schon im Wort. Ein Bild ist dabei auch die gängige API-Lösung.

Aber ich denke gute Windows kundige Leute wie "mk-soft" oder "RSBasic", etc. könnten da noch was beisteuern.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
chi
Beiträge: 90
Registriert: 17.05.2007 09:30
Wohnort: Linz - Austria

Re: [GDI+] Wie bekomme ich DoubleBuffering ?

Beitrag von chi »

/:->

Code: Alles auswählen

BeginPaint_(Window,@PS) 

tdc = CreateCompatibleDC_(ps\hdc)
bmp = CreateCompatibleBitmap_(ps\hdc, ps\rcPaint\right, ps\rcPaint\bottom)
old = SelectObject_(tdc, bmp)

If GdipCreateFromHDC(tdc, @Graphics) = #S_OK
  If GdipCreatePen1($FF0000000,2,#UnitPixel,@Pen) = #S_OK
    GdipCreatePen1(ii | $FFFF000F,i/10,#UnitPixel,@PenRed)
    GdipCreateSolidFill($FF000000,@Brush)
    GdipFillRectangle(Graphics,Brush,0,0,400,400)
    GdipDrawRectangle(Graphics,PenRed,50,50,i,i)
    GdipDeleteBrush(Brush)
    GdipDeletePen(Pen)
  EndIf
  GdipDeleteGraphics(Graphics)
EndIf

BitBlt_(ps\hdc, 0, 0, ps\rcPaint\right, ps\rcPaint\bottom, tdc, 0, 0, #SRCCOPY)        
DeleteObject_(SelectObject_(tdc, old))
DeleteDC_(tdc)

EndPaint_(Window,@PS)
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Re: [GDI+] Wie bekomme ich DoubleBuffering ?

Beitrag von Fluid Byte »

Was soll das denn bringen? Jetzt werden wieder Windows-Event-Nachrichten missbraucht um eine Animation wiederzugeben. Du musst künstlich WM_PAINT senden (InvalidateRect_()) nur um kontinuierlich den Inhalt zu aktualisieren. Das kann man dann mit jeder Nachricht machen, die Logik dahinter ist fehlerhaft. Außerdem hast du es verkompliziert und das DoubleBuffering von nativen PB Befehlen in GDI umgewandelt, nicht GDI+. Komplett sinnlos ...
Windows 10 Pro, 64-Bit / Outtakes | Derek
Benutzeravatar
chi
Beiträge: 90
Registriert: 17.05.2007 09:30
Wohnort: Linz - Austria

Re: [GDI+] Wie bekomme ich DoubleBuffering ?

Beitrag von chi »

Bin schon auf die Kritik gespannt... ;)

Code: Alles auswählen

Import "gdiplus.lib"
  GdiplusStartup(*Token,*Input,*Output)
  GdiplusShutdown(*Token)
  GdipCreateFromHDC(HDC.i,*Graphics)
  GdipDeleteGraphics(*Graphics)
  GdipCreateSolidFill(Color.i,*Brush)
  GdipCreatePen1(Color.i,Width.f,Unit.i,*Pen)
  GdipDeletePen(*Pen)
  GdipDeleteBrush(*Brush)
  GdipFillRectangle(*Graphics,*Brush,X.f,Y.f,Width.f,Height.f)
  GdipDrawRectangle(*Graphics,*Pen,X.f,Y.f,Width.f,Height.f)
EndImport

Structure GdiplusStartupInput
  GdiplusVersion.i
  *DebugEventCallback
  SuppressBackgroundThread.i
  SuppressExternalCodecs.i
EndStructure

Enumeration
  #UnitWorld
  #UnitDisplay
  #UnitPixel
  #UnitPoint
  #UnitInch
  #UnitDocument
  #UnitMillimeter
EndEnumeration

Procedure.i WindowProc(Window.i,Message.i,wParam.i,lParam.i)
  Protected Graphics.i
  Protected Pen.i
  Protected PenRed.i
  Protected Brush.i
  Protected ii.i
  Static i.f = 50  
  Select Message
      
    Case #WM_TIMER
      i + 5
      If i > 200
        i = 50
      EndIf
      ii = i      
      GetClientRect_(Window, cRect.RECT)
      hdc = GetDC_(Window)
      tdc = CreateCompatibleDC_(hdc)
      bmp = CreateCompatibleBitmap_(hdc, cRect\right, cRect\bottom)
      old = SelectObject_(tdc, bmp)      
      If GdipCreateFromHDC(tdc, @Graphics) = #S_OK
        If GdipCreatePen1($FF0000000,2,#UnitPixel,@Pen) = #S_OK
          GdipCreatePen1(ii | $FFFF000F,i/10,#UnitPixel,@PenRed)
          GdipCreateSolidFill($FF000000,@Brush)
          GdipFillRectangle(Graphics,Brush,0,0,400,400)
          GdipDrawRectangle(Graphics,PenRed,50,50,i,i)
          GdipDeleteBrush(Brush)
          GdipDeletePen(Pen)
        EndIf
        GdipDeleteGraphics(Graphics)
      EndIf
      BitBlt_(hdc, 0, 0, cRect\right, cRect\bottom, tdc, 0, 0, #SRCCOPY)       
      DeleteObject_(SelectObject_(tdc, old))
      DeleteDC_(tdc)
      ReleaseDC_(Window, hdc)
      
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Procedure.i Window()
  Protected Window.i
  Protected Event.i
  Protected GDI_Startup.GdiplusStartupInput
  Protected GDI_Token.i
  Window = OpenWindow(#PB_Any,#Null,#Null,400,400,"GDI-Test",#PB_Window_ScreenCentered|#WS_OVERLAPPEDWINDOW)
  If Window
    GDI_Startup\GdiplusVersion = 1
    GDI_Startup\SuppressExternalCodecs = #True
    If GdiplusStartup(@GDI_Token,@GDI_Startup,#Null) = #S_OK
      SetWindowCallback(@WindowProc())
      SetClassLongPtr_(WindowID(Window), #GCL_HBRBACKGROUND, GetStockObject_(#BLACK_BRUSH))
      SetTimer_(WindowID(Window), 0, 15, 0)
      Repeat
        Event = WaitWindowEvent()
        Select Event
          Case #PB_Event_CloseWindow
            Break
        EndSelect
      ForEver
    EndIf
  EndIf
EndProcedure

Window()
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: [GDI+] Wie bekomme ich DoubleBuffering ?

Beitrag von NicTheQuick »

So. Feierabend. Thema erledigt. :roll:
Bild
Gesperrt