[RESOLVED] Ellipse Button on Property Window (again)
Okay, I sort of dropped out of the other thread discussing this because it used thunks & subclassing, and it was only for the IDE's design-time. So, it was only to make my life "prettier", and had nothing to do with my users. Given all of this, I figured I'd never actually use it because I'd never put my IDE's stability at risk just for my own design/authoring time to be "prettier".
However, Stuck came along and (sort of) showed how to do it without thunks or subclassing. He pointed out the "Use This Page in Property Browser" option that can be assigned on a "per property" basis. This gives us the ellipse button (almost).
In the attached project, I've worked out how to totally eliminate the flash of the Property Page. However, I've yet to figure out how to tell which property clicked the ellipse button in the property page's code. That's my current dilemma.
To see it, download and load the attached project. No need to execute it. We're talking about things in design-mode. Just open Form1, select one of the UCs on Form1, open your Property Window (F4), and then click the ellipse on SomeProp1 (or SomeProp2 or SomeProp3). From the Property Page's code, I can't figure out which one was clicked (nor from the actual UC's code).
I suppose I could find the Property Window's handle and start exploring its children to see which had the focus. However, before I dove into that, I thought I'd throw it out here and see what others had to say.
Personally, this all seems stable enough that I might actually use it for some of my UCs.
Take Care,
Elroy
EDIT1: Okay, before someone else says it, I know I could create a separate Property Page for each property of each UC (that wanted an ellipse). However, that pushes it over the edge for me. It's just got to be more self-contained than that before I'd actually use it. Ideally, if the Property Page's code can figure out which property was clicked, I'd pass its name back in the callback to the EllipseCallback sub in the UCs.
Last edited by Elroy; Oct 3rd, 2017 at 04:08 PM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
1. A property page was the original option in that previous post. But he didn't want to use a property page just for selecting a file. Granted, your solution only uses it to create the ellipsis.
2. A Public Sub EllipseCallback() in the UC is not a great idea... Don't want to make something public that the user can call if they shouldn't. If you don't find a better workaround, at least make it hidden. Just a suggestion
3. Place this before you exit your PropPageHandle routine. Should check for a zero hWnd in HideAndClose.
Debug.Print hWnd
I figured I'd never actually use it because I'd never put my IDE's stability at risk just for my own design/authoring time to be "prettier".
Not a strong argument if the subclassing is sound. And if it is sound, the control wouldn't crash once compiled because the 'user' wouldn't be able to break into the code and foul things up. And also keep this in mind, you aren't making it prettier for you, you are doing this for the user of the UC. If the UC will only be used by you to be compiled into your project vs a stand-alone ocx, there are other approaches to get a file dialog from a property without a property page or subclassing.
To perform a crash:
a. Place a stop on the "On Error GoTo 0" on UserControl's Terminate event.
b. Hit the ellipsis button and wait for the code to hit that stop after displaying your msgbox
c. In the immediate window, open it if necessary, type: ? 1=1 and execute that
d. Press F5 to continue with the code - crash
Trying to terminate the property page from within the property page, before it is displayed, seems to cause a crash in many scenarios. I gave up on that idea awhile back. I did find a way to safely do that, but only after it was displayed which is not desired in this case.
Just the fact that you can crash it without using subclassing, to me, indicates it is not safe to do what you are trying. It won't crash if the SendMessage call isn't made. Since COM classes are creating/managing these windows and VB probably has its hooks into it, terminating the window outside of the COM class may be partly to explain? The fact that you are trying to destroy the window in 3 different events, seems to back up that idea.
Memory leaks (GDI-related) appear to be occurring also. If rem out all 3 HideAndClose calls, and click the ellipsis button say 10 times. The GDI objects displayed in Task Manager level off. But by allowing those calls, it doesn't level off, it keeps growing slowly. This is likely a result of circumventing the natural closing of the property page?
Above critical critiques made, good attempt. Don't know if you want to continue pursuing the idea. Think it is not a bad idea. Those that want ellipsis capability without a displayed property page, may find your solution slick.
Edited: I still think it is doable but with subclassing, without leaks. The idea is to subclass the property page and its grandparent. Prevent the WM_SHOW from getting to the grandparent and when the property page gets a WM_SHOW, prevent that and call the close method from the COM class (DispCallFunc API). Just thinking out loud on that one.
Last edited by LaVolpe; Oct 3rd, 2017 at 05:16 PM.
Insomnia is just a byproduct of, "It can't be done"
I truly can't see myself designing UCs for others, but who knows. I hadn't really even thought about that.
You've also given me a few other things to think about. Regarding the crash, you jumped through enough hoops that I feel that I'm still pretty safe on that front, especially once a UC is debugged and "just used".
Regarding the memory leak, that's another problem. Those bug me big time. Actually, I suppose I don't really need to destroy the Property Page container. Maybe just keeping it hidden is enough. However, I'd need to test and make sure that didn't foul up anything else (and that it would truly stay hidden). Because that Property Page container just re-configures when another control is clicked (appearing to use the same container). That's actually why I destroyed it. Let the IDE re-create it if it wants. But that must be related to what's causing the memory leak.
In the meantime I have been drilling into the Property Window. I've got the handle to its ListBox, but it doesn't seem to respond the same as other ListBoxes with respect to LB_GETTEXT nor LB_GETTEXTLEN. LB_GETCOUNT and LB_GETCURSEL work just fine. However, LB_GETTEXTLEN always returns 4, and I can't make LB_GETTEXT work at all.
I'd show you some code, but it's all a mess right now from me playing around with it. Maybe I'll clean it up and post it later.
If I could get that to work, I could get the property name, and just pass it back as an argument in my call to EllipseCallback. That way, when multiple properties have ellipse buttons, I'd know which one was using it.
Again, thanks for the VERY thoughtful review.
Best Regards,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
In the case of a UC for my use only and using a FileName property for example... I'd think I'd code it something like this:
Code:
Property Get FileName() as String
FileName = m_FileName
End Property
Property Let FileName(Value As String)
If Value = " " Then
' show file dialog and set selected file to m_FileName variable or do nothing if canceled
Else
m_FileName = Value
End If
PropertyChanged "FileName"
End Property
The simplicity of this is that we can paste a complete file name in the property window and we can blank it out. If we want a dialog, we just pass a space. This KISS principle can also be used in runtime. Because the UC is only used by its creator (you), you can decide how simple/complex it should be.
Showing a file dialog is just an example. Any action can be performed as needed and the property only needs to make sense to the creator.
Insomnia is just a byproduct of, "It can't be done"
For some reason, when I click on Form1 to get to the Properties window, I get an error statement.
Subsequent "OK's" gets me to a Form with 3 PB's on it, which kinda tells me it's defaulting to a
test project of mine, not yours.
Nonetheless, could you post a screenshot of your Form and one of the UC's Properties window.
However, Stuck came along and (sort of) showed how to do it without thunks or subclassing. He pointed out the "Use This Page in Property Browser" option that can be assigned on a "per property" basis. This gives us the ellipse button (almost).
Hey Elroy, just out of curiosity over here, It sounds like you were not able to successfully make use of the Ellipse code I posted. I'm currently using it to prompt the user to select files and use them within the UC. I have had it running for a while now without any problems other then a quick flash that only sometimes is visible.
I guess my question comes from the '(sort of) and (almost)' notations in your post. Is there are part of the code that doesn't work? Thanks.
Declerations:
Code:
Option Explicit
Dim File_Spec As String
Initialize:
Code:
Private Sub PropertyPage_Initialize()
On Error Resume Next
CommonDialog.ShowOpen
File_Spec = CommonDialog.filename
End Sub
Paint:
Code:
Private Sub PropertyPage_Paint()
Dim ctl As Object
Dim Handle As Long
Set ctl = SelectedControls.Item(0)
If (Len(File_Spec) <> 0) Then
ctl.Browse = File_Spec
End If
Set ctl = Nothing
Handle = FindWindow(vbNullString, "Property Pages")
Call SendMessage(Handle, WM_SYSCOMMAND, SC_CLOSE, 0)
End Sub
At times I've gone a step further and instead of placing the entire file specification into the Browse property, I parse the file spec and only include the file type surrounded by parenthesis similar to how VB does it when selecting an image for a PictureBox.
You can place code in the Browse Let Property to perform any processing you would like to run once the user has selected a file. If you have multiple properties that you would like to have an Ellipse button on, then simply duplicate the short code above substituting the Browse property name with a new one and your good to go.
Last edited by stuck-n-past; Oct 4th, 2017 at 05:21 AM.
Please know I didn't mean any offense whatsoever. I suppose, with the code you posted, it wasn't clear how the property would actually get set with the return of the common dialog. Also, at least the way you presented it, it wasn't possible to put the ellipse button on several (more than one) properties of a UC. And also, I was trying for a neatly-wrapped-up solution that could easily be "thrown into" any UC I was developing with minimal effort/customization to make it work.
From that perspective, I saw your post as a nice framework and exciting novel idea that needed to be carried forward to completion. And, to that end, that's why I started this thread.
@Krool:
Yeah, I figured I was overlooking something fairly straightforward. I've got a busy day today, but I'll definitely take a look at the EditProperty event. That, and some consideration of LaVolpe's notes, might put this thing to bed.
@LaVolpe:
Yeah, I hear ya with respect to the KISS principle. It's still sort of cool though to get an ellipse button. For instance, I've got an RtfLabel and RtfButton control I often use. Basically, these controls allow me to have full RTF text on the caption. To use them, I right-click and then "Edit" the controls. This pops up a little word-processor-like form that overlays the actual control. From here, you can copy-paste from WordPad. Also, this little word-processor also has a font combo, font color selection, picture insert etc. Once this little word-processor is closed, everything goes into an RtfText property. It'd just be nice if that RtfText property had an ellipse button.
And that's just one example. If it was bullet-proof and easy to use, I'd probably make use of that ellipse for several things. Also, right-click / Edit only gives us one option, whereas the ellipse allows us as many "advanced" property options as we'd like.
@Spoo:
I'm not sure what to say. I just downloaded the project from the OP, and it loaded just fine for me. Here's a picture of Form1 (in design mode):
And here's a picture of my project window once it gets loaded:
Again, a bit busy today, but I'll get back to all of this.
Best Regards,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Elroy - no problem, I wasn't bothered in the least by your post, but I will say it was nice to hear you say in your latest post that there was no offense intended. Hehe - as a typical programmer, I was more concerned over the possibility that my code wasn't working, then worrying about political correctness or hurt feelings.
I think at times people get hurt unintentionally simply by the words used in describing issues. I know that my words and posts have not always been welcomed as they were intended.
In my other post where I uploaded a project showing how to get an Ellipse button to show up, I hadn't submitted a full / complete project. I decided to remedy that with another upload that's a bit more finished.
Load the project and open the form.
Click on the green UC which should bring up the IDE Property List.
Click on the Browse Property to get the Ellipse button to appear.
Click on the Ellipse button to have the CommonDialog open.
Select any file and click open.
Last edited by stuck-n-past; Oct 4th, 2017 at 09:17 AM.
Spoo: Try re-downloading / re-unzipping it, and then try clicking on the VBP again. I just have to believe that your VBP got borked somehow. I can't imagine what else it could be.
Say Spoo, you do show your extensions for ALL files, right?
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Ahhhh, Spoo, you're trying to open the project from within the ZIP file. You've got to drag everything out of the ZIP file into some folder you've created, and then open the project from there.
When you attempt to open things directly from a ZIP file, it just unpacks the file you've double-clicked into a "temp" folder, which is what you're seeing. But it doesn't unpack all the other files that are also in the ZIP file. That's your problem.
Take Care,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Okay, I'm personally calling this one quits. And it was really just a self-indulgence anyway, so no big deal.
I got very close by just hiding the Properties Pages window (using SetWindowRgn) in the PropertyPage_EditProperty before making a call_back to the UC. Just hiding (no close) in this one spot allowed the ellipse to work without any flicker whatsoever. In fact, in many respects, that worked quite well. Also, I'm quite confident that I was getting the correct hWnd for the Property Page while in the PropertyPage_EditProperty, and, only doing this hide (no close), I'm quite confident that I was circumventing any memory leak.
However, there was one issue I just couldn't solve. As we know, other controls use this Property Pages form (such as SSTab). Furthermore, if we have Property Pages open, we can click around from one control to the other and get their properties. The problem is, if I had just used my custom ellipse, the Property Pages window was hidden. Therefore, if you right-click/edit an SSTab (or click (custom) on the Properties Window), the Properties Page wouldn't show. If you clicked around a bit, it would eventually show, but not immediately.
I played around trying to fix that problem, but never came up with a bullet-proof solution. I'm not sure there is one without going back into memory-leak territory (and/or possibly back into flicker territory). Therefore, I'm letting this procrastination project fade into the ether.
Y'all Have a Great Weekend,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: [RESOLVED] Ellipse Button on Property Window (again)
Hi Dilettante,
No no, this had absolutely nothing to do with run-time. It was all IDE design-time.
Also, I've got no desire to create OCX UCs for others, so it was all just for my own use.
I just really liked the idea of being able to design UCs with properties with an ellipse button that I could use in any way I wanted. However, also, just because of the way I am, if I was going to do it, it had to be flawless. That it, there could be no memory leaks, no flashing, and it had to "play well" with all other controls (that may also use the Property Pages window). If I couldn't accomplish this flawlessness, I didn't see the point, given that it was just for me. I mean, there are other methods of running code for a specific property of a UC. If I can't make the ellipse perfect, I'll just use those (which I now do in several cases).
I hope that clears up any confusion.
Best Regards,
Elroy
EDIT1: Also, maybe that'll help to explain why (in my case), I wouldn't be interested in using thunks or subclassing to do it. I'm sure there are rock-solid thunks, but I've got to have a very good argument to use them during design-time in the IDE, and these ellipse buttons weren't that strong of an argument.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.