This is reaching way back in the memory vault.
Legacy application, VB6, standard TextBox control on a Form.
When you start typing text, it is right against the left edge. I want to set a left margin so that the first character appears inset by some amount.
There are a dozen examples online, all the same, but none of which change the left margin for me. What could I possibly be doing wrong?
Here is the standard example and the one I am using:
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const EM_SETMARGINS = &HD3
Private Const EC_LEFTMARGIN = &H1
Private Const EC_RIGHTMARGIN = &H2
' Set the TextBox's margins.
Private Sub SetMargin(nLeft As Integer, nRight As Integer, lhWnd As Long)
Dim lLongValue As Long
'nRight needs to be in the hi-word, so we multiply by 65536
lLongValue = (&H10000 * nRight) + nLeft
SendMessage lhWnd, EM_SETMARGINS, EC_LEFTMARGIN Or EC_RIGHTMARGIN, lLongValue
End Sub
This absolutely does not change the left margin of the text in my TextBox. I have tried values of 10, 100, 1000, and 10000 with no changes.
The TextBox Alignment property is set to LeftJustify.
I have tried Multiline set to True or False. (One example indicated it must be set to True)
I have tried calling SetMargin() in Form_Load and other locations.
I must be missing something silly. But have looked and spent a couple hours Googl'ng on this and can't seem to find the missing piece. Any ideas from anyone?
Adding my test situation. An empty Form with only one TextBox in it and the following code:
Option Explicit
Private Sub Form_Load()
SetMargin 100, 100, txtMargin.hwnd
End Sub
I don't know why, but I figured out a scenario that allows this to work on my legacy VB6 project.
Prior to this, when it wouldn't work, I had Declared the SendMessage function in a standard VB module (.bas). And I put the Public SetMargin() method in that module as well. Then called it from my Form. When I did this, it didn't work.
Now, I put the declaration, defined the constants, and the SetMargin() method in my Form's local code. And voila! It works.
Below is a pic of it with the left margin set to 30. And you can see why I wanted this. I wanted to overlay a Picture control on the TextBox, and have the typing start to the right of that.
Related
I'm using C++Builder 10.3 with a VCL application for Windows. I'm trying to identify a specific item in an AdvPopupMenu by looping through the Items Caption and comparing the Caption to my search text using CompareText(). The Captions have an '&' in the Caption text which I believe is part of the ShortCut feature. This seems to prevent a match when comparing the text.
I have tried setting up the menu items two ways to try and remove the '&'.
//--#1 Menu Setup--
TMenuItem *NewMenuItem;
NewMenuItem = new TMenuItem(MainForm->AdvPopupMenu1);
TShortCut sc2;
sc2 = TextToShortCut("(None)");
NewMenuItem->Caption = "Google";
NewMenuItem->ShortCut = sc2;
//--#2 Menu Setup--
TMenuItem *NewMenuItem;
NewMenuItem = new TMenuItem(MainForm->AdvPopupMenu1);
NewMenuItem->Caption = "Google";
NewMenuItem->ShortCut = NULL;
Below is my loop to search for the AdvPopupMenu item.
UnicodeString SearchFor = "Google";
UnicodeString TestCaption;
for(int i=0; i<MainForm->AdvPopupMenu1->Items->Count; i++){
TestCaption= MainForm->AdvPopupMenu1->Items->Items[i]->Caption;
if(CompareText(SearchFor , TestCaption)==0 ){
//This CompareText always fails
//TestCaption looks like this "&Google" or this "G&oogle"
}
}
How can I setup the AdvPopupMenu Caption to contain no '&' and make the CompareText work?
The &s are important. Without these, keyboard users like myself will find your application more difficult to use.
I think your best solution is to use the StripHotkey function in the Vcl.Menus unit to remove the ampersand character before you pass the caption to CompareText. (In addition, instead of testing if CompareText returns 0, it's better to use the SameText function.)
That is, don't attempt to create the menu items without the ampersand character, and don't try to remove it from the menu items. Only remove the character from the string you pass to the comparison function.
Also notice that the ampersand character is not related to the ShortCut property. The ampersand character makes the next character underlined in the menu item caption, telling the user than he or she can press that key to activate the menu item, but only when the menu is open. On the other hand, the ShortCut property adds a right-aligned text like Ctrl+A or Shift+Ctrl+N or F2 to the menu item, and these shortcuts are available even when the menu isn't open. Hence, these are different features.
I have a Lua function where I build a table of value and attempt to add it to a global table with a named key.
The key name is pulled from the function arguments. Basically, it's a filename, and I'm pairing it up with data about the file.
Unfortunately, the global table always comes back nil. Here's my code: (let me know if you need to see more)
(Commented parts are other attempts, although many attempts have been deleted already)
Animator = Class{}
function Animator:init(atlasfile, stringatlasfriendlyname, totalanimationstates, numberofframesperstate, booleanstatictilesize)
-- Define the Animator's operation mode. Either static tile size or variable.
if booleanstatictilesize ~= false then
self.isTileSizeStatic = true
else
self.isTileSizeStatic = false
end
-- Define the total animation states (walking left, walking right, up down, etc.)
-- And then the total frames per state.
self.numAnimationStates = totalanimationstates or 1
self.numAnimationFrames = numberofframesperstate or 2
-- Assign the actual atlas file and give it a programmer-friendly name.
self.atlasname = stringatlasfriendlyname or removeFileExtension(atlasfile, 'animation')
generateAnimationQuads(atlasfile, self.atlasname, self.numAnimationStates, self.numAnimationFrames)
end
function generateAnimationQuads(atlasfile, atlasfriendlyname, states, frames)
spriteWidthDivider = atlasfile:getWidth() / frames
spriteHeightDivider = atlasfile:getHeight() / states
animationQuadArray = generateQuads(atlasfile, spriteWidthDivider, spriteHeightDivider)
animationSetValues = {atlasarray = animationQuadArray, width = spriteWidthDivider, height = spriteHeightDivider}
--gAnimationSets[#gAnimationSets+1] = atlasfriendlyname
gAnimationSets[atlasfriendlyname] = animationSetValues
--table.insert(gAnimationSets, atlasfriendlyname)
end
Note: when using print(atlasfriendlyname) and print(animationSetValues), neither are empty or nil. They both contain values.
For some reason, the line(s) that assign the key pair to gAnimationSets does not work.
gAnimationSets is defined a single time at the top of the program in main.lua, using
gAnimationSets = {}
Animator class is called during the init() function of a character class called Bug. And the Bug class is initialized in the init() function of StartState, which extends from BaseState, which simply defines dummy init(), enter(), update() etc. functions.
StartState is invoked in main.lua using the StateMachine class, where it is passed into StateMachine as a value of a global table declared in main.lua.
gAnimationSets is declared after the table of states and before invoking the state.
This is using the Love2D engine.
Sorry that I came here for help, I've been picking away at this for hours.
Edit: more testing.
Trying to print the animationQuadArray at the index gTextures['buganimation'] always returns nil. Huh?
Here's gTextures in Main.lua
gTextures = {
['background'] = love.graphics.newImage('graphics/background.png'),
['main'] = love.graphics.newImage('graphics/breakout.png'),
['arrows'] = love.graphics.newImage('graphics/arrows.png'),
['hearts'] = love.graphics.newImage('graphics/hearts.png'),
['particle'] = love.graphics.newImage('graphics/particle.png'),
['buganimation'] = love.graphics.newImage('graphics/buganimation.png')
}
Attempting to return gTextures['buganimation'] returns a file value as normal. It's not empty.
My brain is so fried right now I can't even remember why I came to edit this. I can't remember.
Global table in Main.lua, all other functions can't access it.
print(gTextures['buganimation']) works inside the function in question. So gTextures is absolutely accessible.
Table isn't empty. AnimationSetValues is not empty.
I'm adding second answer because both are correct in context.
I ended up switching IDE's to VS Code and now the original one works.
I was originally using Eclipse LDT with a Love2D interpreter and in that environment, my original answer is correct, but in VS Code, the original is also correct.
So Dimitry was right, they are equivalent, but something about my actual Eclipse setup was not allowing that syntax to work.
I switched to VS Code after I had another strange syntax problem with the interpreter where goto syntax was not recognized and gave a persistent error. The interpreter thought goto was the name of a variable.
So I switched, and now both things are fixed. I guess I just won't use LDT for now.
Solution: Lua syntax. Brain Fry Syndrome
I wrote:
animationSetValues = {atlasarray = animationQuadArray, width = spriteWidthDivider, height = spriteHeightDivider}
Should be:
animationSetValues = {['atlasfile']=atlasfile, ['atlasarray']=animationQuadArray, ['width']=spriteWidthDivider, ['height']=spriteHeightDivider}
Edit: I'm fully aware of how to use answers. This was posted here to reserve my spot for an answer so I could edit it later when I returned back home, which is exactly what I'm doing right now. I'll keep the old post for archival purposes.
Original:
I solved it. I apologize for not posting the solution right now. My brain is melted into gravy.
I will post it tomorrow. Just wanted to "answer" saying no need to help. Solved it.
Solution is basically, "oh it's just one of those Lua things". Wonderful. I'm having so much fun with this language - you can tell by my blank expression.
From the language without line endings or brackets, but forced print parentheses... ugh. I'm going back to C# when this class is done.
I just used the SecondaryShortCuts-Feature of Delphi's TAction. But Shortcuts are defined by Strings, like "F5" or "Shift+F5". Now the problem: On my German Windows the action doesn't fire, because the key "Shift" is called "Umsch" in German!
Does it mean the SecondaryShortCuts-Property is completely useless at design time, because nobody can create applications which work internationally with that?
I could set the key at runtime by translating the VK_SHIFT into the correct name. I tried it via GetKeyNameText but this didn't worked because it gave the long form "Umschalt" not "Umsch". Anybody know the function to get the short version of the key name?
You could try this: Generate the shortcut text from a shortcut:
var
s: TShortCut;
begin
s := ShortCut(Ord('A'), [ssShift]);
Action1.SecondaryShortCuts.Add(ShortCutToText(s));
By the way, these values are determined by the following constants. Have you translated those? And if so, do you need to?:
SmkcShift = 'Shift+';
SmkcCtrl = 'Ctrl+';
SmkcAlt = 'Alt+';
I need to create and manage many simple published properties. I call them auto-properties if they look like that:
private
FTitle: string;
published
property Title: string read FTitle write FTitle;
Usually I create them next way:
Adding property name and type:
property Title: string
Selecting and copying property name Title to clipboard.
Appending the line with read F Ctrl+V write F Ctrl+V ;
Pressing Ctrl+Shift+C and this will generate the private field
Is there any way to exclude steps 2 and 3 to add properties faster? Maybe it is possible to create some macro for this?
Since Delphi 2006 you can use LiveTemplates.
In Delphi XE for example:
type propf and hit Ctrl + J keystroke
write the property name and hit TAB key
write the property type name, hit TAB or ENTER key and you are done
You can find more information on how to write your own Live Templates here:
Delphi Live Templates - http://delphi.wikia.com
Creating Live Templates - http://docwiki.embarcadero.com
I use macros for that purpose.
For example I have model with fields
private
FTitle: string;
FName: string
FAge: Integer
then I copy-paste the fields into published section and create macro
Goto first field and hit Home
Hit Ctrl + Shift + R to start recording macro
Use Crtl + ->, Crtl + <- and End keys for navigation and convert first field to property like property Title: string Read FTitle Write FTitle;
After that hit Home and go to next row
Finish macro by hitting Ctrl + Shift + R
For all other fields, just press Crtl + Shift + P
At first it seems difficult, but the skills will pay off.
In XE7 type prom and hit enter. It seems faster.
I am using TAdvMemo. My problem is with the WordWrap property. It works very well when I type text in the text area, but when I add a string to it in code, it has no effect.
I have set WordWrap property to: wwRightMargin and RightMargin property to 80, but not see other property that can help me, so i ask some idea as solve it?
i mean for example:
AdvMemo.Lines.Add(MyString);
where MyString is a string as: 'hello word'. When it is longer than 80 chars, and wrap is enabled, it should wrap to a new line, but instead it's all on the same line.
Try using AdvMemo.InsertText instead. Lines.Add doesn't care about wrapping, it just handles some special chars in the string.
After you added text to adv memo you must update wrap by calling UpdateWrap() function. Here is an example for you:
AdvMemo.Lines.Add(MyString);
AdvMemo.UpdateWrap();
or
AdvMemo.Lines.Text(MyString);
AdvMemo.UpdateWrap();
Be sure that WordWrap property of Adv Memo is different than wwNone.