-
Some questions regarding my project
Hi!
I'm currently working on a small program that helps me learn words in different languages.
I wanted to complete the whole thing and then ask some questions, but the problems I'm having are a bit annoying and I'd like to take care of them before I continue.
Here's the program so far: http://www.mediafire.com/?7yt723jcly14mr8
My main questions are the following:
-How can I have a nice transition from one screen to another? The user should only notice things inside the window changing, not a whole new window emerging.
-How can I get rid of the sound the program makes when the user presses ENTER?
And some other things that aren't vital now:
-How can I detect left or right mouse doubleclicks in a listbox event?
-I'm not sure if I'm taking care of memory correctly.
I used #### signs to mark where these issues are in my program in the files form1.h, lists.h & .cpp, form2.h & .cpp. The number of ### signs shows the importance of the problem, so you'll most likely notice the most important ones :)
The main problems should be pretty clear if you give the program a try.
I didn't encounter any fatal errors, but here as some guidelines to minimize the probability of the program crashing:
-The options whether to ask words randomly or in order; in what language to ask them; what to do if the answer is wrong; and the number of repetitions should work, i haven't implemented the other features yet.
-On the left side a list of words titled "Magyar-Német Állatok I." should appear. Double clicking this opens a new form where you are asked words. If you don't want to learn them, make sure "If answer is wrong: wait for keypress" is selected; then you can just skip the questions by pressing ENTER (this will be good for a quick review of words).
Planned features:
-The ones shown in the options menu but aren't working yet.
-The ability to create/delete lists
-The ability to edit lists: add words, delete words, edit words (add meanings, questions, answers, etc..)
*this is where detecting a mouse double-right click would be nice - left click starts asking a list, right click edits the list.
*So far you manually have to edit the *.list file you want to use
I'm sorry for the long post, I tried to be as to the point as possible. But I did want to give a pretty complete picture of the program, I find that usually makes it much easier for people to help:)
Thanks to anyone who checks it out and can give me some advice!
-Tusike
-
Re: Some questions regarding my project
Post the code here instead of at some external site.
-
1 Attachment(s)
Re: Some questions regarding my project
Sorry, I didn't know I can post files here as well; I don't know if there's anything wrong with mediafire though.
Here's the program: Attachment 29997
Due to the 500kB limit, this contains only the main files of the program. The precompiled header and everything else Visual C++ generated on its own are in the mediafire link.
-
Re: Some questions regarding my project
Most people here doesn't like going to another site and maybe getting spammed with popups.
-
Re: Some questions regarding my project
Quote:
Originally Posted by
S_M_A
Most people here doesn't like going to another site and maybe getting spammed with popups.
The new one from post #3 is a CodeGuru attachment, inlined, as is possible since the forum software update.
Didn't have the time to inspect it yet, though.
-
Re: Some questions regarding my project
I know that. My comment was a reply to
Quote:
Originally Posted by Tusike
I don't know if there's anything wrong with mediafire though
-
Re: Some questions regarding my project
So.. Do any of you know what I can do? Or where else can I ask?
-
Re: Some questions regarding my project
Quote:
Originally Posted by
Tusike
-How can I have a nice transition from one screen to another? The user should only notice things inside the window changing, not a whole new window emerging.
The mere fact that you feel the need to ask this question may indicate a fundamental GUI design issue with your program. Ask yourself: Do you really need the second form?
Hard to judge for me without actually seeing your program. The best impression can, of course, be acquired by seeing the program in action (see the end of the post), but some strategically taken screen shots may also do for starters.
Generally, interaction between two forms actually isn't a subject that's asked and discussed in here too rarely. Unfortunately the forum search is still out of order, but probably any thread having "two forms" or something like "form-to-form-communication" in its title is related and may give you some inspiration. Just scroll a bit back in time in the thread listing.
Quote:
-How can I get rid of the sound the program makes when the user presses ENTER?
It looks like anything you're doing in textBox1_KeyPress() would be better done in a TextChanged handler. That way you wouldn't need to mess around with keyboard input any more which certainly is the reason for that noise.
Actually, there's quite rarely a need to handle the KeyPress event at all, while TextChanged probably is the most-handled text box event of them all. And even if you actually do need a KeyPress handler you should clean it up and do anything possible in a TextChanged handler.
Quote:
-How can I detect left or right mouse doubleclicks in a listbox event?
Like any other control, the list box has a MouseDoubleClick event. The event handler gets passed the mouse position and you can use IndexFromPoint() to determine which item is under the mouse. You may also consider the list view as an alternative control: Its ItemActivate event IMO provides a more natural way of reacting to double clicks.
All the above won't catch a right double click, though. And I don't know of any framework or other library implementation of that. Of course you can implement that yourself, but that would be tideous and, honestly, do you really want to demand from your users to learn that? ;) If you want to provide multiple functions for the right mouse button, do it like all the other apps do it too: Use a context menu. (Perhaps a right click plus modifier key, like shift, can be an alternative, but IMO users are more familiar with context menus. Just no double click, please...)
Quote:
-I'm not sure if I'm taking care of memory correctly.
The general answer is: This is .NET, so don't worry. While resource leaks aren't completely impossible there either (though IMO mostly that won't be memory leaks then), this is the exception from the rule and MS strives to document them (they probably missed a few, but I didn't catch one of those yet). Here's an example of a documented one: The System::Windows::Timer is not subject to garbage collection unless you stop it before disposing the containing object (a form in most cases, probably). They tucked away that caveat into the documentation of one of its properties instead of putting it into the documentation of the class itself. And unfortunately the functionality of that property is so obvious that many developers probably won't ever look there...
The more specific answer, though: You're mixing C++/CLI (i.e. .NET) with a bit of C++ standard library (i.e. native) in your code. Of course that native stuff may cause the usual memory leaks if not used properly. This sort of mixture shouldn't be used unless there's a really good reason to do so (and just convenience is none of them ;)). I didn't look really thoroughly, but AFAICT all the standard library stuff you used is pretty much covered by .NET framework alternatives.
Quote:
I'm sorry for the long post, I tried to be as to the point as possible. But I did want to give a pretty complete picture of the program, I find that usually makes it much easier for people to help:)
I'd suggest not to worry about that. :) Your post is not too long (compare it to mine... :rolleyes:) and decently on-topic.
Unfortunatly, your ZIP file attached to post #3 did give some insight into your code, but it didn't make up a compilable project. Instructions for uploading complete projects:
- Do a clean-up (in the Build menu) on your project in the VS IDE. If you mabe both debug and release builds of the project, you'll need to do two clean-ups as well. Just select each build type as if you were building and instruct the IDE to clean up.
- Manually delete the .sdf file from the solution directory (the one with the .sln file in it). The file is not subject to project clean-up, can become quite bulky (see below) and will automatically be rebuilt by the IDE in the background when required anyway.
- Without starting the IDE in the meantime (it would rebuild the .sdf file), zip the solution directory and upload the result.
As per my experience, the .sdf file is bloated by more than one magnitude just by referencing the Win32 API or the native C++ standard library. That way the file can easily become 25 MB and more. Personally, I have never used .NET plus standard C++ library but no Win32 API in a single solution, but according to your description of the first attempt to upload the zipped project and from how I overlook what I know of your project, that seems to have the same effect.
-
1 Attachment(s)
Re: Some questions regarding my project
Quote:
Your post is not too long (compare it to mine...
True, but seeing as I'm the one seeking an answer, I'm only grateful for that. :)
I did a clean-up and everything; last time I figured out that I can delete the *.sdf, but I wasn't sure how I could get rid of the precompiled header (4Mb). The clean-up took care of that, so I hope this one will work:
Attachment 30007
Quote:
Do you really need the second form?
A few weeks ago I asked in the Visual C++ forum how to handle changing screens, and the answer was that I should use multiple forms (along with that I should have posted in this forum). First I tried working with multiple panels, and always toggling their visibility to change the screen, but that didn't really work out.
And yes, I hope that my need to do this, (or a better explanation of what else I could've done), will be clear from the program.
Quote:
It looks like anything you're doing in textBox1_KeyPress() would be better done in a TextChanged handler.
Well, I didn't try it out, but seeing as pressing ENTER doesn't change what's in the textbox, this didn't occur to me. We'll see if it works.
Quote:
Just no double click, please...
I agree. I made this program in Freebasic 2 years ago, where I didn't implement the mouse. UP/DOWN changed the selected list, ENTER started to ask a list, and E started to edit the list. Now, since double clicking starts asking the list, the first idea that occurred to me was for right double clicking to edit the list. The context menu idea is better because I also need a way to delete the list, and add a new list, so I can just add those options to the context menu.
As for the memory problems, the truth is right now I don't care that much, I'm trying my best to make sure everything is handled correctly & marking where I'm not sure. If there is an error, I think that (probably) I will encounter it while using the program, in which case I can go back, find it, and fix it. I once had a pretty tricky memory error in a towerdefense game; sometimes it crashed after 7 minutes of playtime, or 15, or I went through a whole 45 minute game without it crashing; and I found it! So once encountered, I hope I'll be able to fix it :)
-Tusike
-
Re: Some questions regarding my project
Quote:
Originally Posted by
Tusike
I did a clean-up and everything; last time I figured out that I can delete the *.sdf, but I wasn't sure how I could get rid of the precompiled header (4Mb). The clean-up took care of that, so I hope this one will work:
[...]
AFAIK the .pch file will be rebuilt when doing a project build next time (how else could the clean-up simply delete it?), but I didn't really care ever, since, as you stated correctly, the project clean-up takes care of that. I downloaded your file but didn't look inside yet. At least the size looks reasonable.
Quote:
A few weeks ago I asked in the Visual C++ forum how to handle changing screens, and the answer was that I should use multiple forms (along with that I should have posted in this forum). First I tried working with multiple panels, and always toggling their visibility to change the screen, but that didn't really work out.
And yes, I hope that my need to do this, (or a better explanation of what else I could've done), will be clear from the program.
Can you post a link to that thread (you know, that forum search thing... :cry:)? That may provide useful extra information about your project. From what I know by now about your program, panels may definitely be worth consideration. They're sort of a "form on a form", without a visible border, though.
Quote:
Well, I didn't try it out, but seeing as pressing ENTER doesn't change what's in the textbox, this didn't occur to me. We'll see if it works.
If you don't want the Enter key to directly influence a text box you either simply don't make it multi-line or set its AcceptsReturn property to false. A quick check seems to indicate that the latter may not work as expected if the form hosting the text box does not have a default button (AcceptButton), but there's certainly somethinbg else that can be done about it instead of using a KeyPress handler.
Quote:
As for the memory problems, the truth is right now I don't care that much, I'm trying my best to make sure everything is handled correctly & marking where I'm not sure. If there is an error, I think that (probably) I will encounter it while using the program, in which case I can go back, find it, and fix it. I once had a pretty tricky memory error in a towerdefense game; sometimes it crashed after 7 minutes of playtime, or 15, or I went through a whole 45 minute game without it crashing; and I found it! So once encountered, I hope I'll be able to fix it :)
This approach isn't fundamentally different from the way I, and probably many others, write their programs. But by simply not diong things that are known to not be a good idea in the first place, many problems can be prevented up-front.
-
Re: Some questions regarding my project
Link to the thread:
http://forums.codeguru.com/showthrea...Multiple-pages
Quote:
That may provide useful extra information about your project.
I really don't think it will; or at least minimal information as opposed to, say, opening my project... :D
-
Re: Some questions regarding my project
Quote:
Originally Posted by
Tusike
Link to the thread:
[...]
I really don't think it will; or at least minimal information as opposed to, say, opening my project... :D
Well, I don't quite agree. :) Let's look at your very first post in that thread:
Quote:
Originally Posted by
Tusike
I'm currently working on a program that will help me study languages by asking words from a list. What I need is a way to change what's on my Form - there's a different screen in the beginning, then when the program's asking question, another for editing the words in each lists, etc...
How can I change what the user sees, while still working with one Form?
Given that description, to me it looks like a great opportunity to use tabs.
And in fact you seem to already have abandoned the idea of using individual forms in post #3, slightly more than one month ago:
Quote:
Originally Posted by
Tusike
[...] I'm interested in how I can change what's on my window using Visual C++. It's hard to imagine that it's designed to only have a static look... Right now my newest idea was to use these "Panels", each representing a "screen", and then just toggle the panels' visibility and enabled property on and off. Is that the best option available? Using multiple forms seems really weird to me, why would I need more than one window to run my program in? [...]
Finally:
Quote:
Originally Posted by
Igor Vartanov
Actually, what you described looks to me like a sort of wizard. User does some action/settings with one view and then gets to another view, and another view, etc. In regular programming practice it's typically done by tabbed dialog (a main dialog with tab control on top of it) or wizar-like dialog (a dialog with Back/Next/Finish buttons in the bottom area). Both apps use borderless child dialogs with a single dialog visible at particular moment, which visibility is controlled by either tab control or Back/Next buttons. All logic about processing user input is implemented in particular dialog (procedure or class), and main dialog may provide a menu/toolbar handling (or may not, as MFC internally implements command routing mechanism)
Although parts of this paragraph, in particular the end, are rather MFC/Win32-specific, Igor already alluded to the basic idea of using tabs here. And a wizard-style dialog basically is a tabbed dialog without tabs. While tabbed dialogs are natively supported by Windows Forms, wizards are not. There has been a discussion about how to implement them nonetheless here some time ago, and the conclusion was that the best way of doing that probably is using a tabbed dialog but pushing the tabs out of sight. (The idea of using panels was considered too, but eventually abandoned.)
One thing you seem definitely need to get rid of is the Freebasic way of thinking. I don't know Freebasic myself, but from your description it looks like while it does support graphic elements, the Freebasic programs work more like a console application. And that's simply not the way GUI apps are written, even less so nowadays.
-
Re: Some questions regarding my project
Quote:
the best way of doing that probably is using a tabbed dialog but pushing the tabs out of sight.
and that is what for some reason didn't even occur to me. I threw out the tab idea right away thinking that I didn't need those tab things showing, and concentrated on the other two possibilities.
Also, switching the textbox to multiline fixed my problem with the sound! And, since after pressing ENTER I already reset the textbox's Text to nothing / zero-string, it really doesn't matter whether more lines would be possible or not. Plus using the KeyPressEventHandler remained working fine.
Many thanks for all your help so far, I feel I'm good to go! :) I'll post here if I run into any other problems, but I hope I won't.
-Tusike
-
Re: Some questions regarding my project
Quote:
Originally Posted by
Tusike
and that is what for some reason didn't even occur to me. I threw out the tab idea right away thinking that I didn't need those tab things showing, and concentrated on the other two possibilities.
Unfortunately forum search still doesn't work, so I tried to locate the thread using my attachment list, yet to no avail. :( I know I posted sample code there, but apparently as a code snippet, not a complete demo project (though I had one here to play with). If I had found it, I'd have posted a link here for you.
Quote:
Also, switching the textbox to multiline fixed my problem with the sound! And, since after pressing ENTER I already reset the textbox's Text to nothing / zero-string, it really doesn't matter whether more lines would be possible or not. Plus using the KeyPressEventHandler remained working fine.
Actually, this is not what I had in mind; I thought, for instance, the text box already were multi-line and that might at least indirectly contribute to the problem. And I still think using a KeyPress handler without a compelling reason unnecessarily complicates things. But hey... it works! :) :thumb:
Quote:
Many thanks for all your help so far, I feel I'm good to go! :) I'll post here if I run into any other problems, but I hope I won't.
You're welcome! :)
-
Re: Some questions regarding my project
OK, I'm still having problems with the sound when pressing ENTER.
I tried using TextChanged handler, but I don't know how to detect whether ENTER was pressed in that.
Right now, here's the behavior of the textbox:
-If it's not multiline, it works perfectly, except for the sound.
-If it is multiline, there's no sound when pressing enter, and that's good.
The program starts by asking a word - "Dog". I enter "der Hund" + ENTER, it is correct, the program continues.
Then the program asks the next word - "Cat". I enter "die Katze" + ENTER - the program thinks it is false, displays the correct (but same) answer, and asks again. No matter how many times I enter the correct answer, the program thinks it is false.
However, if I press BACKSPACE before typing anything in the textbox, then type "die Katze" + ENTER, it is accepted and the next word is asked...
That seemed pretty weird to me. But it gets worse... I thought perhaps because of the multiline, chr(13) is somehow added to the textbox's text when I press enter (even though for each new word & mistaken word, I always reset textBox->Text = ""). So entered "die Katze" 10 times in a row, each time getting asked again, and then I inserted a breakpoint in my code where the answer was checked, and viewed textBox->Text's value. The debugger showed "die Katze", so I continued - and my answer was accepted....
So basically, if I put in a breakpoint there in my code and press F5, the answer is accepted, otherwise not. I'm completely lost.
-
1 Attachment(s)
Re: Some questions regarding my project
Here's the newest version, if that can make things clearer. The point where I have to insert the breakpoint is in form1.h, sub CheckDef(), and I commented there: Attachment 30023
-
1 Attachment(s)
Re: Some questions regarding my project
Quote:
Originally Posted by
Tusike
[...]
That seemed pretty weird to me. But it gets worse... I thought perhaps because of the multiline, chr(13) is somehow added to the textbox's text when I press enter (even though for each new word & mistaken word, I always reset textBox->Text = ""). [...]
Yes, there is something extraneous in the text box' Text but what's there probably not is exactly what you expect it to be and, more important, not where you think it is.
Programs behaving diferently "in real life" and when debugging is a really bad thing, and I reproduced your test running the program in the debugger, but in order to minimize if not eliminate interference of the debugger with the program I didn't set a breakpoint but added this line right at the beginning of CheckDef():
Code:
Diagnostics::Debug::WriteLine(String::Format("Form1::CheckDef() called, textBox1 contains: {0}",
textBox1->Text));
And this is the output I got from it:
Attachment 30027
Obviously there is something extraneous in it in the second iteration, but why is it before the user input? :confused: [<- rhetorical smiley] Also, when dealing with text boxes, it's not a chr(13) (or CR), in C++ speak called \r, it's a \r\n (AKA CRLF), but this detail is, at least in the context here, of minor relevance.
The prevalent question now is: How the heck did it get there? Actually, you've fallen victim to one of the peculiarities of the KeyPress event. (Yes, I told you so... :p :cool:) This event handler is invoked before the control gets notice of the keystroke. Consequentially this happens (without the breakpoint):
- You type "der Hund" and then hit Enter, thereby triggering the event and initiating execution of the real business code of your event handler.
- The event handler calls CheckDef() which confirms that the answer is correct.
- The event handler clears the contents of the text box.
- The event handler returns.
- Only now the keystroke is passed on to the control for processing, and causes it to add a \r\n at the end of the (at this point empty) contents of the text box. (It wouldn't do that if the text box wasn't multi-line.)
So the string you get in the second iteration is "\r\ndie Katze", but the line break isn't actually part of the "Katze" input, it's a remnant of the "Hund" input.
Setting the breakpoint now introduced this change in behavior, leading to the different results: The breakpoint gets hit between steps two and three. At this time the debugger gets control and at the same time something somewhere passes the keystroke to the text box for processing. When step three is reached, the line break has already been inserted into the text box and gets cleared along with the other stuff already there as was your intention. Consequentially, there's nothing more to insert into the text box at step five.
One possible solution might be to set e->Handled to true after the main business processing of your handler, preventing the text box to process the keystroke. But I didn't check that, and I usually check everything (I can think of... :)) when it comes to keyboard event handlers.
Another solution that I did check successfully is this change to CheckDef() (and the equivalent change to the handling of lang1 a few lines down):
Code:
for (int i = 0; i<Lists::words[WordOrder[CurrentWord]]->lang2->Length; i++)
{if (textBox1->Text->Trim()->ToLower() == Lists::words[WordOrder[CurrentWord]]->lang2[i]->ToLower()) return 1;}
The Trim() removes any potential whitespace of from the beginning and the end of the string, and these line break characters count as whitespace.
Another minor improvement may be the use of a string comparison that is ignoring case by itself, thereby eliminating the need for the case conversion:
Code:
for (int i = 0; i<Lists::words[WordOrder[CurrentWord]]->lang2->Length; i++)
{if (!String::Compare(textBox1->Text->Trim(), Lists::words[WordOrder[CurrentWord]]->lang2[i], true)) return 1;}
The funny thing is that this is exactly the same number of source code characters as the variant above. :) However, I find that stylistically neater and it even may be slightly more efficient in terms of performance (which of course is completely irrelevant here :)).
However, when initially looking at your KeyPress handler, I obviously was so distracted by the bulky comment that I simply overlooked the very first line of the handler, the if (e->KeyChar != (char)13) return;. Now this line means that the actual business part of the handler only is executed in response to hitting Enter, which indicates a perfect case for an accept button click handler, leading me to the (tested) solution I'd eventually like to propose:
The form doesn't have any accept button at all (which actually is not uncommon for an app's main form), so I added one to the second tab page and set the the form's AcceptButton property accordingly. I did not change the button's DialogResult to anything different from the default None because the button shall not close the form like accept buttons usually do. (But AFAIR it wouldn't do so anyway unless the form has been shown as a modal dialog using ShowDialog().) Then I moved everything from the KeyPress handler except the initial if line verbatim to the new button's Click handler and finally removed the KeyPress handler. Oh, I also reverted the text box' MultiLine property to false; it looks like it was never intended to actually be multi-line in the first place anyway. Works great and IMO is much cleaner.
If you don't want your users to see a "Check It!" (that's what I named it) button on that tab, you may move it outside the visible area of the tab page/form. Do not simply make the button invisible, since, just like disabled buttons, hidden buttons not just can't be clicked (obviously), they also don't catch keystrokes.
-
Re: Some questions regarding my project
Well I'd never thought I'd run into such errors... Thanks for the thorough explanation!
For now, seeing as I'm currently in a German course and would wish to use this program before it ends, I just used the String::Compare method, and it works fine, as you said.
I actually finished the asking part of the program, with all the options in the menu working, but as it would be really tedious to write all the *.list files by hand in notepad, I'm working on a built-in list editor. My goal is to get that working ASAP, and it's almost done; however, I will have a few stylistic questions which would make the program faster to use. Right now I'm using two multiline textboxes in which each row represents a language 1 and 2 meaning, that's pretty simple. The questions however complicate things a bit, and I'm not sure I know of the best tools VC provides to do this, but the idea is to have a a multiline textbox store the questions, and have another textbox store the answers to the question that is currently "selected" in the Q textbox. I found the method "GetLineFromCharIndex" to do just that, so I hope it'll work.
EDIT: I decided to limit the number of questions possible to say, 5. I really can't think of any reasons why someone might need more, it'll certainly be enough for now, and it's much easier to implement.
-
1 Attachment(s)
Re: Some questions regarding my project
Quote:
Originally Posted by
Tusike
Right now I'm using two multiline textboxes in which each row represents a language 1 and 2 meaning, that's pretty simple. The questions however complicate things a bit, and I'm not sure I know of the best tools VC provides to do this, but the idea is to have a a multiline textbox store the questions, and have another textbox store the answers to the question that is currently "selected" in the Q textbox. I found the method "GetLineFromCharIndex" to do just that, so I hope it'll work.
It's not impossible to get that to work with two synchronized multi-line text boxes, but it would be quite some work to equip that with half-way decent usability and still be quite hackish.
The really "authoritative" Windows Forms control for this purpose is the DataGridView. Here's a scenario where I use it in one of my own apps:
Attachment 30039
(In fact, that image is a mocked-up combination of screen shots of the real form in action and the same form in Forms Designer, meant to clarify which part of the form actually is the DGV.)
The DGV is very powerful, but unfortunately this incurs quite some complexity in handling it which sometimes might be a bit too much for a beginner. However, I myself have always used the DGV as a "raw control" while it also can be bound to a backing database which may considerably reduce the complexity imposed upon the developer, but I never tried that, as I'm not quite a database guy.
The ListView also can display a cell matrix and so may superficially seem to be a suitible candidate as well, but as-is it only allows editing of the first column. You could add the lacking functionality yourself, but then again you have considerable complexity and it's more hackish compared to using the DGV.
Another option that's particularly interesting if you want to deploy the program to your users with ready-made lists but don't intend to give them the ability to edit the lists themselves, is using an external program like, for instance, Excel to edit the lists and save them as CSV or tab-delimited files. Reading in those files is not natively supported by the .NET framework, but it's fairly easy to write that yourself.
Quote:
EDIT: I decided to limit the number of questions possible to say, 5. I really can't think of any reasons why someone might need more, it'll certainly be enough for now, and it's much easier to implement.
So you're using a matrix of 2 x 5 ordinary text boxes? Sure, that's probably the simplest possible way of handling a small fixed number of table entries. :)
-
1 Attachment(s)
Re: Some questions regarding my project
Yes, this DataGridView thing does seem to have many uses. But I don't think I need it, at least not yet :)
I'm finally almost finished. The user can do everything, except for creating a new list (I still have to look into the best way to do that, I'll probably use the SaveFileDialog).
Attachment 30041
So far I didn't get any errors in the latest version, so it's supposed to be good & working.
I think the 3-reduced-from-5-question thing turned out pretty good, except that of course, it only supports 3 q1 type questions... Oh well. I can live with that for now. The program works with more + q2, so it's only a matter of the editing interface.
My three most important questions for what I plan to do tomorrow:
-If I want to detect keyboard shortcuts (key presses), like "Delete", "F1", "CTRL-S", "ESC", etc... which event should handle those, so it gets detected (without a sound..)? For example, I have a tabpage that displays all the words in a list; I want to be able to edit/delete/add new words using the keyboard, and not right clicking.
-To use my ContextMenuStrips, I first have to left click on an item to select it, then right click to get the menustrip with that item selected. Can I do something to have right-click select that item and bring up the contextmenu, and so avoiding the left-click?
-Is it possible to change the input keyboard? I currently have english, german, and hungarian keyboards added, and it would be great if the program could automatically switch between these as needed, this would save a lot of time in adding new words + when the words are asked in a random language.
-
Re: Some questions regarding my project
Quote:
Originally Posted by
Tusike
-If I want to detect keyboard shortcuts (key presses), like "Delete", "F1", "CTRL-S", "ESC", etc... which event should handle those, so it gets detected (without a sound..)? For example, I have a tabpage that displays all the words in a list; I want to be able to edit/delete/add new words using the keyboard, and not right clicking.
This first thing you should do here is forget about the KeyPess handler, since that only catches character input keys, and only two of those you listed at least remotely belong to that category: Ctrl+S and Esc (which technically, at least from the ASCII perspective, is Ctrl+[). The event in charge here is KeyDown which catches almost everything (thereby increasing the effort you need to filter out the unneeded stuff, though). As you seem to intend to use these keys as a replacement for the menu your program doesn't have, the right instance to hanndle the KeyDown probably is the form. The KeyDown event is subject to the same caveats issued earlier on, but this time it really seems to be the means of choice. And as at least the Del listed here is a keystroke that is also consumed by text boxes, chances are you'll need to set the form's KeyPreview property to true.
There are two keys on your list that are still critical, though. Just recently I tried to intercept and exclusively (but conditionally) handle Esc myself in a modal dialog (that did have a CancelButton) of one of my projects, with the final result (though it took some time to get there) that I abandoned that idea entirely and resorted to an alternative approach not involving that key at all. F1, as the standard Help key, may be subject to some special treatment by the framework as well. I never tried to make personal use of it, but at least you should be on your guard. Like me you may find out that using a different key or a more fundamentally different solution is the better idea.
Quote:
-To use my ContextMenuStrips, I first have to left click on an item to select it, then right click to get the menustrip with that item selected. Can I do something to have right-click select that item and bring up the contextmenu, and so avoiding the left-click?
I didn't ever try that with a list box, but in one of my recent apps I do that with both a list view and a tree view. The list view is completely uncritical in this respect since it actually does select an item upon right click. The tree view does not, however, and for that I have this MouseClick handler:
Code:
System::Void Form1::treeView1_MouseClick(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e)
{
if (e->Button == Windows::Forms::MouseButtons::Right)
m_tnRightClickedNode = treeView1->GetNodeAt(e->Location);
}
In the context menu's Opening handler I then check whether m_tnRightClickedNode is nullptr and if it is (which means the right click didn't hit any node) I apply the context menu to the currently selected node, otherwise to m_tnRightClickedNode. That selected node may be quite some space away from the mouse click in this case, so you may alternatively want to simply refuse to open the context menu by setting e->Cancel to true in the Opening handler.
Quote:
-Is it possible to change the input keyboard? I currently have english, german, and hungarian keyboards added, and it would be great if the program could automatically switch between these as needed, this would save a lot of time in adding new words + when the words are asked in a random language.
It probably is, but I don't know how. Chances are that this only can be done the native way, so you may need interop. But I, as a German, know how tideous it is to enter German umlauts on, say, a US keyboard, even for one who sits in front of a German keyboard many hours a day and perhaps could be expected to know by heart where the respective keys are. You don't expect your users to have a decent collection of international physical keyboards at hand, do you? ;) Aside from the fact that switching physical keyboards during system runtime isn't completely unproblemaic either. Have you considered offering virtual keyboards for languages that are incompatible to the host system's language?
Some additional general notes: Your program already does defy practically any common Windows GUI habit it finds anyway, so asking you to better accomodate to them would come close to demanding a complete rewrite of your program. But mind this: When I started your program the first time, I had no idea how to start the quiz. It took me some time to figure it out. Just a few dozen seconds, but keep in mind that I'm an experienced developer who can ask oneself questions like "What are possible interactions with Windows controls [that in addition I'd need to identify as what they are] that the program's author might expect me to use?". Many "ordinary users" probably would have given up after at most three to five minutes or so, closed your program and then never opened it again.
-
Re: Some questions regarding my project
Your suggestion for using the Opening handler is exactly what I was looking for. I didn't know it's so simple to check which item was right-clicked using e->Location.
Y
Quote:
ou don't expect your users to have a decent collection of international physical keyboards at hand, do you? Aside from the fact that switching physical keyboards during system runtime isn't completely unproblemaic either. Have you considered offering virtual keyboards for languages that are incompatible to the host system's language?
In my freebasic version that's exactly what I did. There I had a .bmp image of all the letter and characters the program accepted as an input, and I had language files that associated a keypress with one of those characters; and the program simply used different language files when waiting for a reply in different languages. Perhaps I'll end up doing something similar; I need to think about it first. Maybe I could have all the textBox's TextChanged or whatever is the best handle redirect it to a single function which does exactly that. We'll see. I was hoping to avoid this though, it was pretty frustrating to implement before :)
Quote:
Your program already does defy practically any common Windows GUI habit it finds anyway
Well, good to know! :D And I don't exactly have "users", though it's probably a good habit to write a program in such a way as if there were. I could include a help menu or something, or some small text instructions in the space at the bottom-right. I'm sure there are tons of better alternatives on the internet, even though I decided to write my own asking program because none of those I saw supported multiple meaning or the ability to add question - which, seeing as german verbs have many forms, or to ask the plural of nouns, etc... is pretty useful in my opinion. But I'm only a hobby-programmer, I've never studied programming and I just started the university in mechatronics & physics, so I probably never will either; what I have fits in to what I'm imagining.
-
Re: Some questions regarding my project
You don't really need bitmap files of the foreign characters. Rather you'll need one or more Unicode-enabled fonts that support your languages, so your text boxes can display them. And if there's still something you can't do with the font and need a character bitmap, you can create it on the fly by printing a character to a memory bitmap, et voil*! :)
When emulating foreign keyboard layouts, I'd suggest you do that with a key translation mapping you handle locally to your program, so you don't disturb other apps running on the system. Seems to me much like what you did in the Freebasic version. I'd further suggest you do the translation based on virtual key codes rather than character codes, making it independent from the host system's locale-dependent keyboard layout. When using virtual key codes, you'd need to hook into the KeyDown event since only that gets to see the virtual key code; both KeyPress and TextChanged merely see the character which is the result of the system's translation of the virtual key code.
And I'd still suggest to provide a virtual keyboard, as an alternative to the physical one but at least as a visual display of the foreign keybord layout. Say I'd start out learning Russian, would it be likely I already know the Russian keyboard layout by heart then? I don't think so... ;) There has been a thread here about building a virtual keyboard as well, but you know, the forum search... :cry:
Quote:
Originally Posted by
Tusike
[...] seeing as german verbs have many forms [...].
If I'm not mistaken the number of different cases in English and German actually is the same, the difference just being that in English they're often expressed using auxiliary words when in German there's a separate verb form for the same meaning, admittedly. Even good ol' Latin has one more case than German. ... and I've heard Sanskrit is really, really scary in this respect... :p
Quote:
[...] what I have fits in to what I'm imagining.
At least for hobby programmers that's probably what's most important. :thumb:
Experience shows that out of the programs I write, those I regularly use myself gradually improve in usability over time, eventually usually becoming the better ones. Not really surprising though, is it? In all of them I try to respect common GUI habits of course, as long as it's adequate.
-
Re: Some questions regarding my project
Quote:
You don't really need bitmap files of the foreign characters.
In Freebasic I did, since there was only one type and size of built-in font.
Quote:
I'd further suggest you do the translation based on virtual key codes rather than character codes, making it independent from the host system's locale-dependent keyboard layout.
I'm not sure how to do that, right now I tested using KeyEventArgs->KeyCode. I didn't figure out how to globally detect the KeyDown event, so I'll create a function and have all the textbox's KeyDown events go there. The function will recieve the KeyEventArgs and the textbox's Text pointer, along with language specifications. The function will evaluate a one-character string based on the language, add it to the Text received as a parameter, and also set the KeyEventArgs Handled to true. So far what I tested, this seemed to be working fine, although I didn't try it out yet on my program, only in a small test-program. No more QWERTZ german keyboard! :P
Quote:
And I'd still suggest to provide a virtual keyboard, as an alternative to the physical one but at least as a visual display of the foreign keybord layout.
Or... I can do what I did in my earlier version. :) That is, give the user the ability to change the virtual keyboard for each language. So for each character, the user presses a key-combination he/she wishes to use, and the KeyCode is stored along with whether shift, control, and alt were pressed or not. That'll provide a few hundred possibilities... And, I don't know about you, but I first like to have the program completely working. After that will I concentrate on things such as adding a visual display, help, and other things.
Quote:
Experience shows that out of the programs I write, those I regularly use myself gradually improve in usability over time, eventually usually becoming the better ones.
Oh, this program has a lot of history. The first version I wrote in QBasic in 7th grade for spanish class, all the words and meanings were hard-coded into the program, with the only "option" being whether to ask them randomly or not!
-
Re: Some questions regarding my project
Quote:
Originally Posted by
Tusike
I'm not sure how to do that, right now I tested using KeyEventArgs->KeyCode.
Yeah, exactly that is the virtual key code, wrapped into an enum value. And KeyEventArgs::KeyData is just KeyCode plus the modifier key flags. I'm not entirely sure about KeyValue since I never used it, but it may well simply be one of the former two in the form of an integer. In the program mentioned earlier where I did some keyboard magic, I needed to deal with both the managed Keys enum and Win32 virtual key codes, and it looks like, regarding the underlying integral value, the two are identical. (But caution: That is true for the key codes, but definitely not for the modifier key flags.) So perhaps KeyValue is just the raw Win32 key code before its conversion to the managed enum.
Quote:
I didn't figure out how to globally detect the KeyDown event, so I'll create a function and have all the textbox's KeyDown events go there. The function will recieve the KeyEventArgs and the textbox's Text pointer, along with language specifications. The function will evaluate a one-character string based on the language, add it to the Text received as a parameter, and also set the KeyEventArgs Handled to true. So far what I tested, this seemed to be working fine, although I didn't try it out yet on my program, only in a small test-program. No more QWERTZ german keyboard! :P
As global as you can (and usually should) get without leaving the .NET territory is handling keystrokes at the form level. But you seem to realy need international input just for a few text boxes anyway, so it's probably better to handle it at that level. Here it can be useful that you can attach a single event handler to more than one control. (Can be easily done in the IDE using the drop arrow at the right end of the event handler field in the control event list.) You can tell apart which control raised the event by checking the sender parameter passed to the event handler and/or directly access the control after safe-casting the parameter to the appropriate control type.
Doing the key-to-character translation in the event handler, manually adding the resulting key to the control's contents and then telling the framework the key has been handled would probably be the way I'd do that too.
Quote:
Or... I can do what I did in my earlier version. :) That is, give the user the ability to change the virtual keyboard for each language. So for each character, the user presses a key-combination he/she wishes to use, and the KeyCode is stored along with whether shift, control, and alt were pressed or not. That'll provide a few hundred possibilities...
That's mostly just a variation of what we discussed above: You give the user the abilty to edit the key-to-character mapping. But while I, as a user, really love things to be configurable, I also expect them to start out with decent default settings so I'm not necessarily required to configure everything from scratch before I can start.
Quote:
And, I don't know about you, but I first like to have the program completely working. After that will I concentrate on things such as adding a visual display, help, and other things.
Separating development (and implementation) of business logic and UI from each other generally is a good idea. This program, however, seems like it's rather UI-intensive and the both components are comparatively tightly coupled, so at least development of one conponent shouldn't be done without keeping an eye on the other component.
Quote:
Oh, this program has a lot of history. The first version I wrote in QBasic in 7th grade for spanish class, all the words and meanings were hard-coded into the program, with the only "option" being whether to ask them randomly or not!
Yeah, QBasic.. That's quite some time ago... :D
-
Re: Some questions regarding my project
I was pretty sure I left another reply before you answered, but I don't see it...
Anyway, what I wrote was that I found the command
Code:
InputLanguage::CurrentInputLanguage = InputLanguage::InstalledInputLanguages[i]
where the number i corresponds to the language's number.
I tested it in a small sample program and there it worked perfectly.
I'm pretty sure there can be some problems with this (e.g. the "i" values for each language differs on different computers), but I'm also sure they can be addressed. It certainly will be faster to implement; and for the user, it's probably easier as well to use, instead of having to map out a whole virtual keyboard when something goes wrong. Even the problem with "i" can be solved if the *.list file contains the description of the input language instead of just the i number. Then I can check if such a language layout is installed or not, and if not, kindly ask the user to add to in the control panel. I'm still not expecting a bunch of users though :D
-
Re: Some questions regarding my project
Yo, looks quite interesting that class; didn't come across that myself yet. And referring to the installed languages by name instaed of index (i) really is a good idea, as in many such cases.
One concern that came to my mind was this, though: The input language is set per thread and basic Windows Forms apps are single-treaded in the first place, but some of your controls will need to process foreign language input while others won't. I'm not going to discuss the consequences of that in detail now, since what follows is even more severe and probably will spoil that approach at a quite basic level...
Your reference to that class made me curious as to what input languages actually are installed on my own system (German XP SP3). So I quickly hacked together this little console app, mostly based on the MSDN sample code from the documentation on InpuLanguage::InstalledInputLanguages:
Code:
// Test17.cpp: Hauptprojektdatei.
#include "stdafx.h"
#using "System.Windows.Forms.dll"
using namespace System;
using namespace System::Windows::Forms;
int main(array<System::String ^> ^args)
{
Console::WriteLine("Installed input languages:");
Console::WriteLine();
for each (InputLanguage ^lang in InputLanguage::InstalledInputLanguages)
Console::WriteLine(lang->Culture->EnglishName);
Console::WriteLine();
Console::WriteLine("Hit <Enter> to continue...");
Console::ReadLine();
return 0;
}
And this is its output on my system - no more, no less:
Code:
Installed input languages:
German (Germany)
Hit <Enter> to continue...
Not really many languages I feel an actual urge to learn more about... :o
So you'd either need to deploy your program with an installer that installs the required additional input languages or require your users to manually do that themselves. Both not really viable options IMO. So there still just remains the third option we already discussed: Autonomically handle key-to-character mapping in your program yourself.
Quote:
Originally Posted by
Tusike
[...] Then I can check if such a language layout is installed or not, and if not, kindly ask the user to add to in the control panel.
As pointed out above, chances are there's no input language installed at all other than the system's default language. So it's quite likely the user will need to do that. Not really convenient IMO, compared to the effort for you on the programmer's end to autonomically support foreign language input.
Quote:
I'm still not expecting a bunch of users though :D
Well, if you consider to ever become a good programmer some time, even just potentially or remotely, then why not acquire some of the skills one such programmer might use right now? :)
-
Re: Some questions regarding my project
Quote:
As pointed out above, chances are there's no input language installed at all other than the system's default language. So it's quite likely the user will need to do that.
Well, considering you want to learn the language, perhaps asking to use they language's keyboard isn't such a big thing. By the way, "installing" a language (at least on windows) isn't that difficult. In fact, you don't need to install it, just add it. Control Panel->Change keyboards or other input methods->Change Keyboards. And there you just add whatever you want from the given list of probably all major languages. XP should be something similar.
So I don't think "installed" here means what you think; as it's already included with your system.
-
Re: Some questions regarding my project
How can I get the two listboxes displaying the words and their paired meanings, to scroll together?
I tried using the MouseWheel event (even though VC didn't have that included in the listbox's "events" list, so I had to manually make it), and setting the two list's TopIndex to the same value there. But for some reason it didn't work, the two lists scrolled pretty much synchronously, but they were mostly off by 2-3 places.
I also manually made a TopIndexChanged event in the code, hoping it would exist as well, but that gave me an error.
EDIT: I ended up using a timer with 10 intervals, making sure the two TopIndex's agree each tick; it works just fine, although I'm not sure if it isn't "wasting" a lot of CPU time.
-
Re: Some questions regarding my project
Yes, events not listed by Forms Designer can be quite helpful sometimes. :) It doesn't quite surprise me that using the MouseWheel event didn't exactly achieve what you wanted, however, simply because there's a bunch of other reasons for the control to scroll.
I wouldn't be too worried about the system load caused by your timer event. (If in doubt you can always simply check the system load imposed by your program using the Windows Task Manager or Sysinternals' Process Explorer.) However, I have an alternative to suggest (that I didn't try, though): the Invalidated event (which isn't among those offered by the Designer either). The idea behind that is that scrolling the control always would require it to be repainted, wouldn't it? Of course there's a bunch of other reasons why the control might need to be repainted, but I guess that way the percentage of unnecessary event handler invocations would be lower than with the timer method and in particular it wouldn't get called ai all if your app doesn't even have the focus, except in case it gets (completely or partially) uncovered when closing or moving another app's window in front of it.
Of course you'd get synchronuous scrolling for free with a two-column list view in details mode, which, however, may not match your design requirements.