Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Add controls via script at design time

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
gibberishh
Cheater
Reputation: 1

Joined: 30 Aug 2021
Posts: 45

PostPosted: Tue Aug 06, 2024 7:58 am    Post subject: Add controls via script at design time Reply with quote

I followed example.ct from https://forum.cheatengine.org/viewtopic.php?t=586842&sid=f6321c5829c9b4e0731fa36868325bdb and got it working for my purpose. First of all, thanks for that.

I have 219 image files (character portraits in a game) and that populates a HUGE menu under Table. Before anyone goes screaming, the portraits are tiny and the CT is around 600KB with everything. However, I despise that long menu of files under Table.

My idea of a workaround for this is to add image controls in design mode and assign the pictures to them, without going via the Add File route. But, here is what happens: I put the form in edit mode and run my script to add the controls. Everything shows correctly. However, the controls are not listed in Object Inspector. Ever the optimist, I save the table in the main window. Now I close the form, open again and everything added via code is gone. [cries in despair] (Note: files are still added to the table, I intend to delete them after they are populated at design time.)

Obviously, I don't want to manually add 219 image controls in the scrollbox. So my question is this: is there a way to use Lua to add these controls at design time so that they will stay on the form?

Thanks!

Fully working code:
Code:
function ShowPortraits()
-- frmPix is the form; all these named objects are created at design time (Table > Create form)
-- frmPix.tabM, despite the name, is a group control for male portraits (need this for the caption it shows, which scrollbar control doesn't)
-- frmPix.tabF is a group control for female portraits (earlier used tabs and then changed them to group controls, hence the bad naming)
-- frmPix.tabM.sclPixM is a scrollbar control for male portraits
-- frmPix.tabF.sclPixF is a scrollbar control for female portraits
  local img = {}
  local cols = 7
  local bspace = 3
  for x,g in ipairs({"M","F"}) do
    local ctrls = {}
    for i=0,127 do -- don't worry about the iterator; some numbers don't have files associated, in total I have 105 F and 114 M files
      local f = findTableFile(g..i..".png")
      if f then
        img[i] = createImage(frmPix.ComponentByName["sclPix"..g])
        img[i].Autosize = true
        img[i].Name = f.Name:sub(1,-5)
        table.insert(ctrls, img[i])
        if (#ctrls-1)%cols > 0 then -- puts the images in a neat grid, in this case of 7 columns
          img[i].anchorSideLeft.control = ctrls[#ctrls-1]
          img[i].anchorSideLeft.side = asrRight
          img[i].BorderSpacing.Left = bspace
          img[i].anchorSideTop.control = ctrls[#ctrls-1]
          img[i].anchorSideTop.side = asrTop
          img[i].BorderSpacing.Top = 0
        else
          img[i].anchorSideLeft.control = frmPix.ComponentByName["sclPix"..g]
          img[i].anchorSideLeft.side = asrLeft
          img[i].BorderSpacing.Left = bspace
          img[i].BorderSpacing.Top = bspace
          if #ctrls==1 then
            img[i].anchorSideTop.control = frmPix.ComponentByName["sclPix"..g]
            img[i].anchorSideTop.side = asrTop
          else
            img[i].anchorSideTop.control = ctrls[#ctrls-1]
            img[i].anchorSideTop.side = asrBottom
          end
        end
        local s = f.stream;
        img[i].Picture.loadFromStream(s)
        img[i].OnClick = SetPortrait -- a separate function that does things when the image is clicked
      end
    end
  end
  portraitsLoaded = true -- global var to prevent re-running of this code
end

_________________
It's not cheating. It's playing by my rules.
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1528

PostPosted: Tue Aug 06, 2024 10:09 am    Post subject: Reply with quote

This code and example may be more understandable in your case.

1) 25 images have been added for example usage. Arrange them in the code according to yourself. (Look at the warning lines written as 105 and 114.)
2) Mouse wheel option has been added to the code. (Active on TrackBar and Image boxes.)
3) You can run functions based on image order on image clicks. (You can do this with "fIndex" and "mIndex".)
4) Important factor; You need to create image names in order. (In the example table, they are shown as "F_1, F_2, F_3..")

5 ) Below is an example table connection and the code used:
CT Link : https://www.mediafire.com/file/xqfytc7b1esxe9a/Example_1.CT/file

Code:
if frm1 then frm1.Destroy() frm1=nil end
DP1=getScreenDPI()/96
frm1=createForm()
frm1.height=290*DP1 frm1.width=600*DP1
frm1.PopupMode=0 frm1.caption="frm1"
frm1.Position="poDesktopCenter" frm1.ShowInTaskBar="stAlways"
frm1.BorderStyle="bsSingle"
-------------------------
local frmPix = {}
----------------------- frmPix.bckImg1 ----- 
frmPix.bckImg1=createImage(frm1)
frmPix.bckImg1.AutoSize=false
frmPix.bckImg1.height=200*DP1 frmPix.bckImg1.width=200*DP1 frmPix.bckImg1.left=50*DP1 frmPix.bckImg1.top=30*DP1
frmPix.bckImg1.Stretch=true
-----------------------
----------------------- frmPix.bckImg2 ----- 
frmPix.bckImg2=createImage(frm1)
frmPix.bckImg2.AutoSize=false
frmPix.bckImg2.height=200*DP1 frmPix.bckImg2.width=200*DP1 frmPix.bckImg2.left=350*DP1 frmPix.bckImg2.top=30*DP1
frmPix.bckImg2.Stretch=true
-----------------------
----------------------- frmPix.trcBar1 ----- 
frmPix.trcBar1=createTrackBar(frm1)
frmPix.trcBar1.AutoSize=false
frmPix.trcBar1.height=25*DP1 frmPix.trcBar1.width=280*DP1 frmPix.trcBar1.left=10*DP1 frmPix.trcBar1.top=240*DP1
-----------------------
----------------------- frmPix.trcBar2 ----- 
frmPix.trcBar2=createTrackBar(frm1)
frmPix.trcBar2.AutoSize=false
frmPix.trcBar2.height=25*DP1 frmPix.trcBar2.width=280*DP1 frmPix.trcBar2.left=310*DP1 frmPix.trcBar2.top=240*DP1
-----------------------

--############################################################################--
--############################################################################--
frmPix.trcBar1.Min=1
frmPix.trcBar1.Max=11 -- 105
frmPix.trcBar2.Min=1
frmPix.trcBar2.Max=14 -- 114
frmPix.trcBar1.Position=1
frmPix.trcBar2.Position=1
frmPix.bckImg1.picture.loadFromStream(findTableFile("F_1.png").stream)
frmPix.bckImg2.picture.loadFromStream(findTableFile("M_1.png").stream)
local fIndex = 1
local mIndex = 1
--------------------------------------------------

frmPix.trcBar1.OnMouseWheelDown=function(sender)
  if sender.Position==11 then -- 105
    sender.Position=11 -- 105
  else
    sender.Position= tonumber(sender.Position) + 1
  end
end

frmPix.trcBar1.OnMouseWheelUp=function(sender)
  if sender.Position==1 then
    sender.Position=1
  else
    sender.Position= tonumber(sender.Position) - 1
  end
end


frmPix.bckImg1.OnMouseWheelDown=function()
local sender = frmPix.trcBar1
  if sender.Position==14 then -- 114
    sender.Position=14 -- 114
  else
    sender.Position= tonumber(sender.Position) + 1
  end
end

frmPix.bckImg1.OnMouseWheelUp=function()
local sender = frmPix.trcBar1
  if sender.Position==1 then
    sender.Position=1
  else
    sender.Position= tonumber(sender.Position) - 1
  end
end

--------------------------------------------------

frmPix.trcBar2.OnMouseWheelDown=function(sender)
  if sender.Position==14 then -- 114
    sender.Position=14 -- 114
  else
    sender.Position= tonumber(sender.Position) + 1
  end
end

frmPix.trcBar2.OnMouseWheelUp=function(sender)
  if sender.Position==1 then
    sender.Position=1
  else
    sender.Position= tonumber(sender.Position) - 1
  end
end


frmPix.bckImg2.OnMouseWheelDown=function()
local sender = frmPix.trcBar2
  if sender.Position==14 then -- 114
    sender.Position=14 -- 114
  else
    sender.Position= tonumber(sender.Position) + 1
  end
end

frmPix.bckImg2.OnMouseWheelUp=function()
local sender = frmPix.trcBar2
  if sender.Position==1 then
    sender.Position=1
  else
    sender.Position= tonumber(sender.Position) - 1
  end
end

--------------------------------------------------

frmPix.trcBar1.OnChange=function(sender)
fIndex = sender.Position
src = "F_"..sender.Position
frmPix.bckImg1.picture.loadFromStream(findTableFile(src..".png").stream)
end


frmPix.trcBar2.OnChange=function(sender)
mIndex = sender.Position
src = "M_"..sender.Position
frmPix.bckImg2.picture.loadFromStream(findTableFile(src..".png").stream)
end

---------------------------------------------------
---------------------------------------------------
function SetPortraitF()
      showMessage("You clicked on image number "..fIndex.."!")
end

function SetPortraitM()
      showMessage("You clicked on image number "..mIndex.."!")
end

frmPix.bckImg1.OnClick=function()
SetPortraitF()
end

frmPix.bckImg2.OnClick=function()
SetPortraitM()
end

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
gibberishh
Cheater
Reputation: 1

Joined: 30 Aug 2021
Posts: 45

PostPosted: Tue Aug 06, 2024 11:27 am    Post subject: Reply with quote

Apologies if I was not clear... I already have working code using findTableFile(), in exactly the format and structure that I need. The problem is that findTableFile() requires me to use Table > Add file, which then generates a totally useless (at least in my case) menu full of 220 filenames.

I want to be able to add image controls at design time via code to be able to circumvent CE's file handling.

Your trackbar is cool, but it still uses runtime loading of images from the _files_ loaded into the table (as opposed to images that are stored within the image control's Picture property).

For clarity: if at design time I manually add an image control, click Picture and Load a file into it, that is NOT added to the Table menu. It is stored as a pic (ASCII translation) within the image control. I want to be able to generate such image controls once at design time via code, save the form, and never have to deal with the Table menu or findTableFile().

_________________
It's not cheating. It's playing by my rules.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4706

PostPosted: Tue Aug 06, 2024 12:52 pm    Post subject: This post has 1 review(s) Reply with quote

Maybe `saveCurrentStateAsDesign` is what you're looking for?
Code:
assert(UDF1, 'create form in Table -> Create form')

if UDF1.CEImage1 then
  print'image already exists!'
  UDF1.show()
else
  print'creating image'
  local img = createImage(UDF1)
  img.Name = 'CEImage1'
  img.Picture.assign(MainForm.Logo.Picture)

  UDF1.saveCurrentStateAsDesign()
end

You could also concatenate all the image table files into a single stream and store that stream as a single table file

_________________
I don't know where I'm going, but I'll figure it out when I get there.


Last edited by ParkourPenguin on Tue Aug 06, 2024 1:15 pm; edited 1 time in total
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1528

PostPosted: Tue Aug 06, 2024 1:14 pm    Post subject: This post has 1 review(s) Reply with quote

As far as I understand, you don't want the images in the table.
If I understand correctly, I will give you 2 options and you can choose one of them:

1) Upload all the images to a storage server and call them from the table via "Internet", upload and use them. (This option uploads the images only to the table, not to the PC.)

2) Store the images in a desktop folder and upload and use them from there.

(3.. I will not recommend ImageList. It may be a pixel concern!)

Which one?

Otherwise, all the images will still be saved in the form in the form design or in the "Add file" option.
For a lighter table, I recommend option number 1.

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
gibberishh
Cheater
Reputation: 1

Joined: 30 Aug 2021
Posts: 45

PostPosted: Tue Aug 06, 2024 10:37 pm    Post subject: Reply with quote

Oh. ParkourPenguin's suggestion looks promising. Am going to try saveCurrentStateAsDesign() first. Will return later and let you'll know how things work out.

Thanks both of you for all your suggestions!


Update:
Here's what I've ended up doing. saveCurrentStateAsDesign() was no bueno. The code-added controls never show up in Object Inspector so they are never saved along with the form/table (at least that's my uneducated reasoning).

So I ran my original script, took a screenshot of the whole grid and saved that as two images (M, F). Then I manually added 2 image controls in design mode, and loaded these canvases into them.

Modified my script to add fixed-size image controls without loading any picture into them (i.e., they are transparent/invisible). They sit exactly on top of each portrait because the code that positions them is the same from before (through which I took the screenshot). The portrait Ids I need went into an array instead of looking up the table files.

Now I don't need any table files for images. The canvases are stored as part of form data. Opened the CT in a text editor, removed the whole <Files></Files> block, and now I'm golden.

_________________
It's not cheating. It's playing by my rules.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4706

PostPosted: Wed Aug 07, 2024 12:55 am    Post subject: Reply with quote

gibberishh wrote:
The code-added controls never show up in Object Inspector so they are never saved along with the form/table (at least that's my uneducated reasoning).
Did you try my example code? It works fine for me
  1. Open a new CE instance
  2. Copy & paste that code into the Lua script window
  3. Click Table -> Create Form
  4. Execute the Lua script (the new image GUI component won't show up in the object inspector until you close and reopen it, but that's irrelevant)
  5. Save the table (File -> Save as...)
  6. Close CE and open a new instance
  7. Load the CT file you just saved
  8. Execute the Lua script- the image was saved properly

I'm glad you got it working anyhow

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
gibberishh
Cheater
Reputation: 1

Joined: 30 Aug 2021
Posts: 45

PostPosted: Wed Aug 07, 2024 4:48 am    Post subject: Reply with quote

Yes, your code works perfectly. The differences between your code and mine are:

1. For img.Picture.assign() I have to assign it via a stream (as I am doing 219 images via code and I don't know how else to access pictures) instead of assigning an existing Picture object. Note: My assign code (different from the loadFromStream one in the first post) does show the images correctly.

2. Instead of createImage(UDF1) I'm using createImage(UDF1.ScrollBox1) as I need the user to be able to scroll through the images.

Other than that, my image controls do have unique names (same as yours).

I'm not sure, but I suspect either 1 or 2 might be causing the controls to not save with the form.

Much thanks to all of you anyway. Your idea of combining the images into a single stream... I didn't quite do that, but did that in a roundabout way.

UPDATE:
This was bothering me so I did a little more investigating. Now I got it to work! This little change fixed everything. All the controls are added to the scrollbox on the form and stay even after the form is closed Very Happy Thank you thank you thank you ParkourPenguin.
Note: The OnClick event of the controls is not saved (yes, the function being called exists). I even tried separately assigning the event via Lua code after the controls got added. No happiness. But that's fine; I simply shift-selected all the controls in Object Inspector and set their OnClick event in one go.
Code:
      img[i] = createImage(frmPix)
      img[i].Parent = frmPix.sclPixM

_________________
It's not cheating. It's playing by my rules.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4706

PostPosted: Wed Aug 07, 2024 1:36 pm    Post subject: Reply with quote

Parent / owner are different concepts. Generally the form should own everything unless you have a good reason otherwise (I'm not familiar enough with lazarus or pascal to say what such a reason could be)

Setting method properties to strings that are the names of global functions seem to save properly:
Code:
function UDF1_imageClicked(img)
  print'clicked'
end

...

img.OnClick = 'UDF1_imageClicked'
If the global function isn't defined, then this won't work
_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
gibberishh
Cheater
Reputation: 1

Joined: 30 Aug 2021
Posts: 45

PostPosted: Wed Aug 07, 2024 2:52 pm    Post subject: Reply with quote

Oh, good to know. When creating controls at runtime (not in design mode), simply assigning a function to it works -- i.e., not just ctrl.OnClick = function() ... end but also ctrl.OnClick = NamedGlobalFunction.

I was not aware of assigning function names as strings. Not the first... or even the last thing I would have thought of!

Will keep the owner thing in mind from now on.

_________________
It's not cheating. It's playing by my rules.
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1528

PostPosted: Wed Aug 07, 2024 3:32 pm    Post subject: Reply with quote

When you create the table before and outside the function, you may be able to use the generated control as in the example.

Code:
local img = {}

function ShowPortraits()
-- ...
img["x"..i] = createImage(frmPix) -- or "parent" createImage(frmPix.sclPixM)

end

img.x1.OnClick=function() print(1) end
img.x2.OnClick=function() print(2) end

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites