Jump to content

Daklu

Members
  • Posts

    1,824
  • Joined

  • Last visited

  • Days Won

    83

Everything posted by Daklu

  1. Auto-populating is a potential cause, but you'll notice I don't have any auto-populating folders in this project. (And I don't have any hidden away in other virtual folders.) I've been running across this more frequently the last couple weeks. I suspect it has something to do with renaming/moving classes and methods, but I don't have a repro case.
  2. Let me clarify... From a technology standpoint I agree they are very cool and it's nice to finally get a viable form of electronic ink that doesn't cause eye strain. From a consumer standpoint I'm not interested in the slightest. I have always found electronic documents less usable than hard copies--especially if it's a document I'm likely to reference a lot. I think the non-textual cues (smudges, a slightly torn page, knowing where I am in the book simply by holding it, etc) from the book help me organize all the information and provide shortcuts for my brain when I'm rereading it. Electronic documents remove those cues. More than that, I wouldn't buy a microwave that only cooks Kraft foods. I'm not inclined to buy ebooks that require a $200+ electronic device in order to use. (I don't buy online music that I can't burn to cd either.) Cat, do you use it primarily for leisure reading or work-related documents?
  3. Recently I found myself making identical changes to all of my class accessor methods, so I modified the WriteTemplate.vit found in <LVx\resource\Framework\Providers\LVClassLibrary\NewAccessors\BaseAccessorScripter>. When I attempted to create an accessor method LV couldn't find WriteTemplate.vit, even though it was clearly searching in the correct folder. Even after selecting the correct file LV wouldn't create the accessor VI for me. Any ideas?
  4. Funny. Personally I don't see the appeal of electronic readers. I guess I'm a Luddite for saying so, but I still prefer paper to ebooks for just about everything.
  5. We tried using the merge paradigm for a while before switching back to locking. There are a couple problems with using scc branch and merge patterns: Labview frequently recompiles the VIs during development, even if you haven't changed that particular VI. If you and another person both make changes to different VIs, but each of those changes causes a third VI to recompile, you have to go through the merge process even though nothing has changed from the developer's perspective. That "third VI" sometimes become those "third through thirtieth VIs," and gets very tiring repeatedly going through a bunch of VI that haven't changed. Labview's merge and diff functions work okay for individual VIs, but they don't work at all for .lvproj, .lvlib, or .lvclass files. The lack of .lvclass support is a real killer for us. If I end up with a check in conflict with a .lvclass file, the best thing to do is close the project, get latest, reopen the project, and recreate all my changes. (Yes, sometimes that's a lot of work that gets thrown away.) There's simply no good way to merge any of those file types and given the way Labview works they change very often. I like the idea of branch and merge, but in practice it just doesn't work very well in Labview.
  6. Thanks for the response Yair. I was able to remove the guilty files by deleting all the contents and resaving them. Still don't understand why I couldn't remove them in the first place. I wonder if it's a bug or expected behavior in certain situations?
  7. There is no single "proper" way to learn Labview; it depends entirely on your learning style. Some people learn well from books, some by trial and error, some by having a more experienced person around who can answer questions as they come up. Most people do best with a mix of several learning methods. Regardless of which learning method works best for you, learning Labview (or any programming language) requires something you can't get from a book or a teacher--experience. Gaining experience takes time. Lots of it. Intelligence, while extremely helpful, doesn't replace the need for experience. If you want more specific suggestions you need to give us more information, such as your programming background and what problems you're trying to solve.
  8. This has happened to me only a handful of times and I've forgotten what caused it last time I saw this. What would cause the option to remove a vi from a project to NOT show up in the context menu? There aren't any VIs that depend on this one. This VI does depend on a few other VIs that I have already removed from the project and are listed in the dependency section. Restarting Labview didn't resolve the problem. Any ideas?
  9. Yeah, it can be tricky figuring out how to apply common patterns to Labview. Observer is particularly difficult because there's so many different ways to do it, each with advantages and disadvantages. The community as a whole hasn't settled on the best implementation. Most use queues to transfer information between the subject to the observer. I prefer to write the subject so that it exposes user events that observers can choose to register/unregister for on their own schedule. It requires more framework code, but I think it results in a more robust solution and better encapsulation. If you haven't worked with user events much they can be rather quirky. Here's the topology I would start with: This prevents your event logger from getting too tightly coupled to your modules and allows you to easily reuse it in other projects. The simpler implementation is to have the module manager receive events from the modules. When it receives an event that needs to be logged, it creates a log entry and sends that to the event logger. Any logic for deciding what and when to log is contained in the manager. The manager also maintains control over the modules, starting and stopping them as needed. The more complicated implementation has the event logger registering for the events from each module directly. I really don't see any advantages to this though. If you're concerned with the module manager being overburdened it would be better to create an app specific log controller that makes the decisions on what to log.
  10. Another one? Did I miss the first one? Sounds very interesting. Did you use native LV toolkits for the processing the video or did you interface to external equipment? Oh, NOW you've done it... *scrambles to find the book while trying to remember where my ascii chart is*
  11. The difference is in what data is being sent with the user event. Your example puts a parent object in a user event typed with a child object. I'm restricting myself to putting a child object on a user event typed with a parent object. I think the key is in the invisible link between the Generate User Event prim and the event structure. Notice the for loop in your example. The Generate User Event prim *thinks* both queues are typed with the parent object, so it doesn't object to sending a parent object down them. The data type in the event structure is defined by the wire sent into the Reg Event prim at design time, so at runtime the parent object is automatically cast as a child, which is can't fully support. In my example there's a coercion dot on the Generate prim, indicating the child object is being upcast to the parent, which is perfectly legal. The silent typecast at the event structure is simply casting the child object from a parent back into the child--also legal. Putting the wrong child class or a parent object does cause problems, so I've tried structuring the framework to prevent the event producer from doing that. Thanks for the heads-up. I'll hide the cookware. Yes, I think it does. In my system each component encapsulates it's message queue internally so the mediator (central handler) isn't even aware of them. I keep the component object's data in a private SEQ so there's no need for a response queue; any sub vi requesting data just grabs it off the queue. From the mediator's perspective it drops a vi asking the component to do something and wires it up. The sub vi returns the result. Simple. The complexity of passing messages between threads is hidden in private class methods. More importantly, I only have to think in that level of detail for a single component at a time. I'm not constantly faced with managing multiple queues. Once the components are developed and tested to my satisfaction I can 'forget' about that level of detail and focus on application logic. If you can, I'd strongly suggest you take the jump into OOP. I have yet to meet anyone who has really learned OOP decide that the 'old' way is better. (Aside from specific high performance applications where c or assembly are needed.)
  12. Singleton and Observer aren't mutually exclusive. A class can be a singleton, a class can be an observer, or a class can be a singleton observer. Lots of people implement loggers as singletons and are quite happy with them. Whether or not it works for you depends on your specific requirements. If you ever need to keep more than one log in your app then you'll have to implement a new singleton class for each log. (You could also change the singleton source code every time your logging requirements change, but I don't recommend that.) If you need to dynamically change the logging at runtime (such as enable/disable logging certain events, logging events in more than one log file, or changing which file an event gets logged to) I'd consider using an observer. The singleton is much easier to implement. The observer decouples the process from the logging, is much more flexible, and is more reusable.
  13. My initial guess would have been a silent shutdown or lockup since that's what happens to me 96% of the time. But since Norm jogged my memory on the dynamic dispatching error I think he's probably right. I'm running into that error more frequently these days... (The error text is, "This dynamic subVI cannot execute because the needed member VI cannot be found.") Seeing that bug in '09 has me a bit concerned that what I'm doing may be violating the rules of 8.6. I think I'm okay, but it never hurts to check... Is there anything wrong with typecasting a child class user event into a parent class user event, aside from the fact that it's possible for the event producer to send the wrong EventData child class along with the event?
  14. Cool trick. As a (very) amateur magician I'll just say the technical aspects of the trick aren't particularly difficult. His presentation is A++ though.
  15. Give the child event a method and try to call it in your second loop. I'm curious what error Labview comes up with.
  16. I got a chance to look over your framework. As I said earlier, I'm not familiar with 7.1 so I can't fairly comment on the implementation. I suspect that it is a very good solution given the tools that are available in that version. Personally, I don't like the idea of a message bus at the application level. It encourages direct communication between application components, which doesn't scale well at all. Direct communication creates a lot of communication paths to monitor. If I have an application with 5 components, I already have 10 communication paths to keep track of. Adding a 6th module to satisfy some new requirement leaves me 15 paths to keep in my head. Pretty soon it just gets too complicated and impossible to figure out what's happening when. Direct communication also leads to dependencies between those components, which limits reusability. I was debugging an app recently that used direct communication and one module was receiving a message that was causing it to go into an unexpected state. It was very difficult not only to figure out where the message was coming from, but what state the application as a whole was in that caused this bug. These days if I'm going to have (or event think I might end up with) more than 3 modules I use a mediator to centralize the communication. It's much easier to control what's going on in the app. I did know about this, but I've struggled trying to figure out how to best use it. I don't want my modules to export a single registration wire for all internal events. The strong typing of the wire prevents me from adding new events to the module without breaking legacy code. I experimented with exposing a registration wire for each event but I didn't like that either, though the reasons escape me at the moment. I really like the idea of encapsulating an Init event though; I had not thought of that. I have noticed a lot of instability in 8.6 when using classes as user event types. I spend so much time experimenting with different ideas and changing things around I don't have a repro case or even a general idea of what might be causing it. I'll be sure to let someone know if I ever narrow it down. The bottom half of your diagram also illustrates why my suggestion of keeping the registration wire strongly typed but allowing the user event wire to be polymorphic isn't feasible. Thanks for the info.
  17. I remember when you posted that tip on the dark side, though I didn't know F. Schubert == Black Pearl. I read through the thread at the time but didn't fully understand it and didn't have time to investigate the code. Of course I'd completely forgotten about it when the time came for me to tackle the same problem! I'll have to dl the code and give it a look-see. The problem with the unregister event prim is that it unregisters all the events for a given event structure. You can't selectively unregister the events. It seems to me that prim should be reserved for cleanup when the event handling code is exiting. Your comments did get me thinking about a hole in this framework: What if the client exits without destroying the user event? The event manager could potentially maintain a large array of unmonitored events. I'm not sure if there's a good solution to this--I'll have to think on it for a while.
  18. Paul, which edition of EA do you use? I checked out the website and it looks like it is trying to be more than just a UML tool. It also wants to be a code generator and project management tool (with unit testing and resource tracking options.) What features have you found particularly useful and what features are less useful fluff?
  19. Speaking of Labview for Everyone, we all know who Jim Kring is, but who is Jeffery Travis and why isn't he on the forums?
  20. I assume you are referring to the Destroy User Event prim? What is it that seems wrong to you? I've never used 7.1 so I'm not familiar with what can and can't be done in it. 8.6 doesn't crash when unregistering for an event after it has been destroyed. It doesn't even throw an error. I suspect you're right about discarding the destroy. Using error 1 to shutdown the producer is a convenient shortcut. I don't use it that way in my template because it limits the flexibility in how I can use the producer. (I developed this mainly with an eye towards using it with active objects, though it could also be used with single threaded applications.) I can't have my consumer stop receiving the events without shutting down the producer, which I may not want to do. Or, I might want to start up an active object without anyone receiving events and have it run in the background while consumers dynamically connect (register for a user event) and disconnect (destroy the user event) from it as needed. IMO it is a better general solution to have independent methods to start and stop the AO rather than linking it's execution to the user event. I can imagine situations where you would want the AO to shutdown automatically when it is no longer needed. If you had multiple independent clients that had no knowledge of each other then none of them would know whether or not they should shut it down. In other languages this is typically done by having the AO keep an internal count of the number of clients who need it and automatically shut down when that reaches 0. It wouldn't be difficult to implement that in Labview. Given that typical dev efforts often include aborting VIs and incomplete error handling, I frequenty find the AOs running with no way to shut them down. I've toyed with the idea of implementing a watchdog timer; when the timer triggers the AO would automatically shut itself down. Clients would have to reset the timer periodically to prevent the shutdown. I haven't implemented that mainly because I don't really want to burden the client with a parallel reset loop but the idea is floating around in the back of my head.
  21. It turns out upcasting the child data object to the EventData object didn't work out as well as I had hoped. So I tinkered around with it for a while and came up with a better solution. I ended up with what I think will be a highly reusable EventManagerTemplate code module that meets almost all of my goals. Adding a new event only requires deriving a new MyEvent class and a new MyEventData class with a single Create sub vi for each of them (though you do need to add getter methods to MyEventData if it carries data), and adding one GetMyEventRefnum vi to the EventManager class. No need to create duplicate RaiseEvent or DestroyEvent methods. No need for the event consumer to type check the event data object in the event structure, OR to downcast it to the proper event data subclass. If there's enough demand I'll try to spend some time cleaning it up and documenting it. No promises on how soon I could post it though... it would likely be at least a week. In the meantime, here's a screenshot of a quick example I rigged up. ------------------------------------- I've reconsidered. Rather than throwing an error, how about forcing an upcast to the parent object at the Reg Events prim? The registration wire would still be strongly typed, which as near as I can tell is really the one that matters, and the user event wire could be polymorphic. (Maybe that's what's happening in 2009?) Not on this project unfortunately. What happens when you try to wire a parent class user event and child class user event to the same output node in a case block? Ah, I think I understand. If the command subclass knows what vi has the additional information it needs to execute it's process, it can obtain a reference to that vi at runtime and acquire the data it needs from the fp controls. Am I close?
  22. I'd take it a step further... try to code up your object model. Usually the object model I design on paper has flaws or consequences that don't become apparent until I start writing the code. Don't forget animals. How many times have we subclassed a Dog class? I think that these examples do a disservice to OOP. They do a reasonably good job of illustrating what inheritance is, but they focus too much on using inheritance and class hierarchies as the core of OO programming. For the longest time I assumed that was the case and my efforts to do OO programming always resulted in more work with little tangible benefit. It wasn't until I started studying design patterns that I really started understanding OOP.
  23. Good info AQ. Can I talk you into a cut 'n paste into the white paper? I'm much more likely to be able to find that again than a post in the Idea Exchange.
  24. Yep. BTW, I'm not familiar with shared variables. When you say a "shared variable event" do you mean a regular user event typed as a shared variable or is it a different construct altogether? Figuring out exactly what functionality belongs in the controller and what belongs in the model (and sometimes even what belongs in the view) isn't very clear. There's a lot of gray in there. I don't quite follow... do you mean the parent command class' execute method has an input for "recipient" that the sub classes can use? Heh... sometimes I wonder. This path is covered with jagged rocks and prickly thornbushes. I don't think many have travelled this way.
  25. Thanks for the input Paul. I've seen your posts on the MVC architecture and my desire to decouple the UI from the business layer led me in that direction. Having a name for it saved me a lot of effort trying to reinvent it, and I've got plenty of half-built wheels hanging around. I believe upcasting the event data object as suggested by AQ and downcasting it in the event consumer is a good enough solution for my immediate application. Not everything I was looking for, but good enough. The rest of it is a theoretical thought exercise to see what I can do using current technology or could do if user events were polymorphic. In a nutshell, I'm looking for the best way for reusable code modules to expose user events to clients. "Best," in this context means several things. Among them are: The code module should not be coupled to any clients. Clients should only be loosely coupled to the module. It should be easy and intuitive for clients to do arbitrary operations on the event data they receive. It should be relatively easy to add new events or extend existing events in the module source code. The code module framework to enable this should not be too large. (Cries of "Code bloat!" from non-OO coworkers still ring loudly in my ears.) I considered the command pattern and know client code could inherit from a Command parent class supplied by the module. The problem with the command pattern in this instance is that it doesn't work well if your command process for some of the sub classes requires additional inputs or outputs. Suppose the client code has registered for the LoadFileError event exposed by my engine, but the client only wants to log those errors if a checkbox on the user interface is true. The client subclasses the LoadFileErrorCommand class provided by the code module and overrides the Execute method. The client doesn't have a good way to get the boolean value into the overridden execute method. The execute method is an override so you can't add terminals to it. You can't add a Set LogToDisk method to the subclass and put that in the event handler without typechecking and downcasting the parent object at runtime, which defeats the purpose of dynamic dispatch in the first place. (It might be possible to set a front panel boolean by getting a reference to the overriding execute vi and using the SetControlValue invoke node. I don't know if that works on controls that aren't on the connector pane. Regardless, I consider that a pretty difficult hoop to jump through for developers of unknown skills who are working on client code.) To allow clients to do arbitrary operations on arbitrary data from arbitrary events, I think you have to expose all the data elements to them, which in turn means the user event structure has to give them a strongly typed EventData subclass at design time. This of course requires the module expose unique events rather than a single generic event. I can do that... so far so good. The inconvenience arises while developing the source code to enable this functionality. Since user events are not polymorphic it is very difficult to operate on the them in sub vis or case statements. This forces me to create and maintain a lot of duplicate code; I have to recreate any common user event processes (Create, RaiseEvent, Destroy, etc.) for each user event the module exposes. Hopefully this image helps explain the problem I'm trying to address. If it seems like I'm trying to find a "one size fits all" solution, you'd be pretty close to spot on. If I had and understood a general solution to the problem I'd be in a much better position to know where I can take shortcuts when applying it to a specific situation, and I'd have a better understanding of what the long term consequences are of using the shortcuts. I've got the hammer, but there are lots of things laying around that don't look like nails. I'm trying to fill out the rest of my tool belt.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.