Idan Gazit

Greenhorn
+ Follow
since Apr 08, 2004
Merit badge: grant badges
For More
Cows and Likes
Cows
Total received
In last 30 days
0
Forums and Threads

Recent posts by Idan Gazit

Hey hey,

This thread helped me solve the tab/jtextarea issue, but the code was not 100% on target. Here was my solution:



This supports both forward (Tab) and backwards (Shift-tab) traversal.

I think there is a better way to do this but I was unable to figure it out. The thinking is as follows:

Events basically get sent to event listeners, in a certain order, and listeners do something (or don't) and consume the event (or don't), and if the event was not consumed, then the next listener in line gets them.

Now, I'm not exactly sure of the naming of these classes, but the ordering of listeners looks something like this for our NoTabTextArea

1. processComponentKeyEvent (in the code above) has first dibs on the key event.
2. sometime later, a focusTraversalKeyEvent (I don't know exactly what it is really called) is supposed to check if the key was a focus-transfer key (tab key or a shift-tab combo for most modern OS's) and tranfer focus accordingly. In the case of JTextArea, either this listener isn't hooked up or it does nothing.
3. The JTextArea's content listener is last in line, gets the key event, and adds a tab to the text.

So the solution above is sort of backwards. An optimal solution would be to reattach #2, that is the focus key listener, so jtextarea acts like every other component (jtextfield, for example). This would also net the benefit of supporting arbitrary traversal keys. Say in the future, Windows 2032 XXXP uses F1 and Shift-F1 for focus traversal. The above solution is hardcoded for tab/shift-tab, whereas the better solution I'm looking for would use whatever Java sniffs out/has defined as the default focus traversal keys, without me having to know them a priori.

So, Swing Gurus -- can you point me in the direction of my fantasy solution? I have tried to figure it out to no avail. The above code works, but it is a hack, and I'd prefer to find the "right way" to do it.

Idan
20 years ago
Hey again,
First off, a bit of clarification, followed by responses:
I know that as far as the JRE is concerned, my message object never was a MsgFoo object to begin with, hence the class cast exception. Perhaps I have framed my question wrong, so let me clarify:
1. All message objects are identical at the data level (they all inherit from BasicMessage).
2. The only thing that a MsgXXX does that a BasicMessage doesn't is a set of functions to deal with the byte stream more intelligently given what I know of that class of messages. It does not add members (well, it adds one static final, a message number for that class of messages).
The underlying byte stream is the same for BasicMessage and also all MsgXXX classes. In fact, all of the underlying stuff in MsgXXX is inherited from BasicMessage.
An example to clarify: MsgFoo is a message about the number of foo's in my widgetron. A message is always 10 bytes, the latter 5 being the payload. The first five are standard across all messages (start byte, checksum, message number, etc...).
So, MsgFoo's stipulate that bytes 1-4 of the payload (0-based) are a little-endian integer value which represents the number of foo's in my widgetron. I could do something like:

which would work for any message, but is cumbersome. Instead, I subclassed BasicMessage into a small forest of classes which allow things like:
myMsgFooInstance.setNumFoos(2);
where the code for setNumFoos() looks like:

See? Basically I subclassed in order to allow more specific interpretation of the same underlying data structure. Perhaps this was not the right way to go?
Since last night I thought that perhaps the subclasses should instead just be static classes which take a basicMessage as an argument to work on? Something like this:

Or something of the like, but it strikes me as another kludge. I must be missing something -- this seems like a too-prevalent situation for there not to be a clean solution....

And now for responses (if I haven't mentioned by name, it's because I feel I've addressed your responses above already):
Dirk:
W/R/T "*I* Know that the message is a MsgFoo" -- The basic thing is that in theory, I could invoke all MsgXXX functions on a basic message -- however, they would provide garbage responses interpretations for messages of a different type. So *I* know that a given BasicMessage happens to be a MsgFoo because I just sent a MsgFoo to my device and I expect one back. The data structure is the same, but the type is different.
So what is now (abundantly) clear to me is that I can't "force" a cast down the tree if my object wasn't originally of the child type.
So, the next question is, why not put all of the various MsgXXX-specific interpretation functions into BasicMessage? Well, it would clutter up the class significantly (150 MsgXXX's * 3-4 interpretation functions per MsgXXX = 450-600 or so functions in BasicMessage). So that's not a real option, plus it sort of defeats the purpose of good OO design and separation.
Eddie:
Yes, there is something in the raw bytestream which indicates which message the BasicMessage is: a message number byte. However, it would force me to write up a 150-200 case long switch or if/else, and maintain that switch every time I invent a new kind of message. Again, defeating the purpose of OO.
What I want is a way to send and receive messages in general fashion, but interpret those messages as whatever message I choose.
No, I'm not serializing/deserializing.
Ok...
Thanks to all for your time!! I sincerely appreciate your assistance and braintime in helping me out with my quandary... Please don't stop posting, I'm sure one of you will eventually smack your forhead and say "this idiot forgot to read page 1 of the java spec," but humor me as I can't seem to dig up a good solution to this on my own.
Thanks again,
Idan
20 years ago
Hey everybody,
I originally posted this to the intermediate forum, but I'm feeling like perhaps the answer is so simple and obvious that I should have posted it in the beginner forum: my original post in the intermediate forum.
I'm sorry for cross-posting; I'm aware that it's bad netiquette -- but please have mercy, I feel like perhaps the question belonged here in the first place!
My heartfelt thanks to all of you who take a look. I'm stumped!
Idan
20 years ago
Michael:
I would certainly rather not create a huge if/else block since I have about 150-200 MsgXXX classes! This also sort of defeats the purpose of inheritance. I have a parent class which I know is a child!
With regards to casting, the rule is that you can't cast down unless what you're casting was originally something further down. For instance:

I believe I have all that correct -- I'm not near a compiler so I can't check it, but that's the grasp I have of things now.
One solution I have thought up is the following, but it strikes me as an inelegant solution:
instead of:

I could do:

Since casting up is automatic, that means I could do:

but this introduces other subtle problems that are too long to explain without showing you all of my code. However, those problems are minor, so it is a *workable* solution, but I am convinced there is some more elegant and correct way to do this. Perhaps I need to restructure my classes somehow, but I feel like I'm missing something basic...
Maulin:


What do you get when you try to do,
System.out.println("Message type:"+msg.getClass().getName()); after line,
BasicMessage msg = myDevice.readMessage();
If that returns you MsgFoo you MUST be able to cast it to MsgFoo...


Although I haven't tried it, I am certain that the message type will be BasicMessage. The code inside readMessage looks like this:

which means that anytime I call:

I am bound to get a bonafide BasicMessage back. My problem is that I thought I could do:

but I can't, because the value returned from readMessage was never a MsgFoo to begin with, so I can't cast down from BasicMessage.
Still frustrated.... I have the sneaking feeling that this is what generics (AKA C++'s "templates") are intended to solve and I'm stuck.
Please tell your friends to take a look at this if you're stumped, I really need to figure this out to get my code working and this is all that is stopping my project from progressing right now!
Thanks again for all of the input, and TIA for those now joining in...
Idan
20 years ago
Hey everybody,
This may belong in the "basic" forum, so feel free to point out that I should skedaddle over there....
My problem is as follows: I'm working on a program which communicates (with external hardware) by means of messages. I've generalized the messaging API I've come up with since there is more than one possible transport layer to my program, but the protocol is identical for all transport layers. So:
class BasicMessage
class MsgFoo extends BasicMessage
class MsgBar extends BasicMessage
class MsgBaz extends BasicMessage
Most functionality is in BasicMessage, which is wholly generic. The various Msg* classes override and extend where they need to for their purposes -- this isn't a place for an interface.
For sending and receiving messages, I've got a "hardware" class which looks something like (pseudocode for brevity):
class Device {
...
public void writeMessage(BasicMessage msg) { ... }
public BasicMessage readMessage() { ... }
}
Now for the problem:
Writing is no problem:
myDevice.writeMessage(new MsgFoo(arg1, arg2, arg3));
Reading, however:
BasicMessage msg = myDevice.readMessage();
MsgFoo mfoo = (MsgFoo)msg; // ClassCastException
So, *I* know that the msg which comes back happens to be a MsgFoo. But at runtime, this fails with a ClassCastException. I thought casting was supposed to allow exactly this kind of behavior, when the programmer knows that a parent class instance is really also a child class instance in disguise.
The creators of java worked around this by adding toXXX() methods for a lot of their code (Integer.toString(), etc... ), but I have many many MsgXXX classes so this would be unweildy and ugly. Redoing BasicMessage as an interface is also no-go, there is a great deal of shared functionality and the whole point of MsgXXX classes is to keep small message-specific info in separate classes with BasicMessage holding the generic guts.
So what do I do? I am at a loss for the "elegant" way around my problem. In the end, what I want to be able to do is to read and write messages, and treat read messages as specific MsgXXX's when I want to....
Thanks!!!
Idan
20 years ago