Graphics Context Help

This forum can be used to talk about general design strategies, new ideas and questions in general related to wxWidgets. If you feel your questions doesn't fit anywhere, put it here.
Post Reply
Moss
In need of some credit
In need of some credit
Posts: 3
Joined: Mon Jul 26, 2021 8:15 am

Graphics Context Help

Post by Moss » Mon Jul 26, 2021 8:22 am

Hi all,

I'm attempting to use a Graphics Context with wxLua. My understanding is that I need to:

1. Draw to the Graphics Context, using a member function, like gc:DrawRectangle(50, 50, 500, 500)

2. At the end of drawing all the things I would like to draw on the Graphics Context, I then need to draw this into a bitmap, like gc:DrawBitmap(bitmap, 0, 0, 1920, 1080).

3. In the Paint Handler event for my frame, I use a regular PaintDC to draw that bitmap onto the frame.

When I run the attached code, I only get a black bitmap. Could someone please explain to me what I'm doing wrong?

Thanks

Code: Select all

require "wx"

red = wx.wxColour(255, 0, 0, 255)
green = wx.wxColour(0, 255, 0, 255)

local screenSizeX, screenSizeY = 1920, 1080
local windowSizeX, windowSizeY = 1920, 1080
local windowPositionX, windowPositionY = 0, 50

local pen = wx.wxPen(wx.wxBLACK_PEN)
local brush = wx.wxBrush(wx.wxBLACK_BRUSH)

local bitmap = wx.wxBitmap(1920, 1080)

local dc = wx.wxMemoryDC()

local frame = wx.wxFrame(
wx.NULL, -- Parent Window
wx.wxID_ANY, -- Window ID
"Graphics Window", -- Name
wx.wxPoint(0 + windowPositionX, 0 + windowPositionY),
wx.wxSize(windowSizeX, windowSizeY),
wx.wxDEFAULT_FRAME_STYLE + wx.wxSTAY_ON_TOP- wx.wxRESIZE_BORDER - wx.wxMAXIMIZE_BOX
)

local gc = wx.wxGraphicsContext.Create(dc)

local function onPaint()
  local dc = wx.wxPaintDC(frame)
  dc:DrawBitmap(bitmap, 0, 0, true)
  dc:delete()
end


frame:Connect(wx.wxEVT_PAINT, onPaint)
frame:Connect(wx.wxEVT_ERASE_BACKGROUND, function () end)
frame:Connect(wx.wxEVT_CLOSE_WINDOW, function(event) os.exit() end)

frame:Show(true)

while true do

  pen:SetColour(red)
  brush:SetColour(green)

  gc:SetPen(pen)
  gc:SetBrush(brush)
  
  gc:DrawRectangle(50, 50, 500, 500)
  gc:DrawBitmap(bitmap, 0, 0, 1920, 1080)
  
  frame:Refresh()
  frame:Update()
  wx.wxGetApp():MainLoop()
  
end
Last edited by DavidHart on Mon Jul 26, 2021 11:09 am, edited 1 time in total.
Reason: Added code-tags

User avatar
doublemax
Moderator
Moderator
Posts: 16383
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Graphics Context Help

Post by doublemax » Mon Jul 26, 2021 4:35 pm

First of all, there is no need to use wxGraphicsContext this way. At least in C++ you can just create a wxGraphicsContext from a wxPaintDC, draw onto it, and that's it. There is no need to draw into a wxBitmap first.

There are several "oddities" in your code which may or may not be responsible for the issue.

- I see no place where you use the wxMemoryDC, where you assign the bitmap to it, or where you draw into it. That's probably the main issue here why the bitmap is black.

- after you assign a bitmap into a wxMemoryDC to draw onto it, you need to un-assign it (or destroy the wxMemoryDC) before you can perform any other operation with the bitmap, e.g. drawing it onto another wxDC

- wxDCs should not be persistent, create them when you need them and destroy them afterwards. I'm looking at

Code: Select all

local dc = wx.wxMemoryDC()
local gc = wx.wxGraphicsContext.Create(dc)
I don't know Lua but these variables look like they don't get destroyed during the lifetime of the program

- where did you get that idea with the "while true" rendering loop from? Usually that would be done with a timer

I would suggest you start with a standard paint event handler which uses a normal wxPaintDC to draw something. You can use a timer to force a regular update.

Once that works, start adding the wxGraphicsContext
Use the source, Luke!

Moss
In need of some credit
In need of some credit
Posts: 3
Joined: Mon Jul 26, 2021 8:15 am

Re: Graphics Context Help

Post by Moss » Mon Jul 26, 2021 10:44 pm

Hi Doublemax,

Firstly, thanks very much for taking the time to reply, I really appreciate it.

The MemoryDC was only created to serve as an argument to the Graphics Context constructor. See below to see how I've now only created it inside the constructor arguments.

I have since made the following modifications to my code:

The gc is now created each loop iteration with
local gc = wx.wxGraphicsContext.Create(wx.wxMemoryDC())

and is also deleted at the end of the loop.

The "while true do" rendering loop works fine for my other programs, which only use WxPaintDCs. I have tried this program both with no main loop, and another version using a hard millisecond wait each iteration. Either way it makes no difference, the bitmap is black. For debugging, I have added the following line:

gc:DrawBitmap(bitmap, 0, 0, 1920, 1080)
bitmap:SaveFile([[C:\ZeroBraneStudio\myprograms\test]]..'.png', wx.wxBITMAP_TYPE_PNG)

And when I open this file, it is indeed a black png. So there seems to be something wrong with how I'm getting the graphics context to draw onto the bitmap.

For clarification, the reason I get the Graphics Context to draw onto the bitmap is that for my other program (which uses a MemoryDC object instead of a Graphics Context), I have multiple objects that modify the bitmap, one after the other, using a MemoryDC, and then the whole bitmap is drawn onto the frame using a wxPaintDC during the frame event handler. This works just fine.

EDIT:
Looks like according to the wxLua reference manual, the GraphicsContext class is not "wrapped" by wxLua. I'm not a software engineer, but I reckon this means it won't work at all haha. It's unusual that the constructor functions seem to be interpreted without errors though... and that I can call member functions like DrawBitmap()... they just don't appear to do anything.

http://wxlua.sourceforge.net/docs/wxluaref.html

User avatar
doublemax
Moderator
Moderator
Posts: 16383
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Graphics Context Help

Post by doublemax » Tue Jul 27, 2021 5:31 am

I don't know which version of wxLua is the latest, but i pulled the repo from https://github.com/pkulchenko/wxlua and searching for "wxGraphicsContext", i see a lot of code. To me it looks like it's implemented.

Code: Select all

local gc = wx.wxGraphicsContext.Create(wx.wxMemoryDC())
I still don't see the part where you assign the bitmap to the memorydc (you need to tell the memorydc where to draw to). You can do that by passing the bitmap to the memorydc constructor, or by calling memorydc::SelectObject( bitmap )
Use the source, Luke!

Moss
In need of some credit
In need of some credit
Posts: 3
Joined: Mon Jul 26, 2021 8:15 am

Re: Graphics Context Help

Post by Moss » Wed Jul 28, 2021 8:59 am

Hi Doublemax, just wanted to say thanks heaps for your help.

I've since solved my problem. I didn't understand what sort of object a Graphics Context actually was. I thought it was its own object that just behaved like an advanced Memory DC. Instead, it's some kind of thing that lives "on top" of a regular Memory DC, and you can't just get rid of the Memory DC after you've used it in the GC constructor. The below working example, for people who've stumbled on this issue:

mdc:SelectObject(bitmap)
local gc = wx.wxGraphicsContext.Create(mdc)

--Do drawing things

mdc:SelectObject(wx.wxNullBitmap)
gc:delete()

All good now, cheers.

Post Reply