SketchPane.addActionListener problem

User 1a8d11549a

27-03-2011 16:46:07

Hi,


I am trying to implement the java.awt.event.Actionlistener interface to catch the MSketchPane "close" event in order to perform some processing before closing the Marvin window.  While I can import java.awt in VB.Net, there's no intellisense entry for java.awt.event. When I enter this namespace manually, I get a message about an ambiguous entry, since multiple "event" methods were present in this namespace. As a side note, in the C# editor, I get a reference 'java.awt.@event' in intellisense, which seems to work.


Is this a known problem? Or are there alternative ways to catch the closure of a JFrame containing a Marvin sketch pane? Any help is much appreciated. 

ChemAxon bd13b5bd77

27-03-2011 18:17:28

Hi John,


I think it is not a bug, neither a problem really, it is done by ilvm. As event is blocked keyword both under vb.net and C#.  Event => @event, this is tha valid change to involve event interface in the framework.
I do not have vb.net installed (C# is the ethalon .net language, I highly recommend you to switch off from vb.net), but I suppose if you open the object browser you will see how vb.net exposes this @event namespace! Object browser is available by hitting F2.


 


You should create a JFrame and an MSketchPane, link them together and init both.
You need an own adapter class.


class YOURSKETCHADAPTER{


         protected class ComponentEvents : [email protected] {


             YOURSKETCHADAPTER  _parent = null;
            internal ComponentEvents(YOURSKETCHADAPTER parent) {
               _parent = parent;
            }


            public override void componentHidden([email protected] ce) {
               _parent.OnClosed();
            }


 


         void Init(){



         if (_content == null) {
            _content = new MSketchPane();


         if (_parentFrame == null) {
            _parentFrame = new javax.swing.JFrame();


         // set it to be docked fill
         _parentFrame.getContentPane().setLayout(new java.awt.BorderLayout());
         _parentFrame.getContentPane().add(_content, java.awt.BorderLayout.CENTER);
         _parentFrame.pack();
         _parentFrame.setLocationRelativeTo(null);


          _parentFrame.setLocation(GetParentLocation(parent));
         _parentFrame.setVisible(true);
         _parentFrame.setTitle(caption);


         _parentFrame.addComponentListener(new ComponentEvents(this));


       }


}

ChemAxon bd13b5bd77

27-03-2011 18:21:30

An explanation to the code snippet:


I think you need the adapter class wrappering up a JFrame and the Sketch pane and link them together.


You need an extension class internally inside your adapter, which entends the  [email protected],  it can be private or protected to access the event dispatcher method (OnClosed), which is also protected and virtual.


In this OnClosed you can raise safty event to the World or you can handle shutdown, clearup statements there internally.


 


if your adapter has a window based parent, you can position the children in center of the parent:
_parentFrame.setLocation(GetParentLocation(parent));

GetParentLocation is a custom routine to calculate out the parent location, this can be a WPF GUI element that has hwnd or any other host frame hosting WInForms for WPF. But this is not a must, just suggestion.


 


Viktor

User 1a8d11549a

28-03-2011 06:39:38

Hi Victor,


Thanks for your code. However, it doesn't solve my intrinsic problem, since it still references the java.awt.@event namespace seemingly unavailable in VB.Net. You will surely understand that I cannot re-write my project from VB.Net to C# in order to be able to access this reference. Interestingly, the namespace 'sun.awt.event' is accessible under VB.Net, so the problem does not generally seem that 'event' is a protected keyword. I also followed your suggestion to use the object browser for java.awt.event, but it simply doesn't appear in the object  list, also not as an alias. - It therefore would be great if someone with a VB.Net installation on Visual Studio 2010 could confirm this IKVM issue of the inaccessibility of the java.awt.event namespace. 


If this should be real, I need to step back from this particular approach to find a another solution. What I want to do is to let the user draw a reaction in MarvinSketch, and whenever the Marvin window is closed (or a Marvin toolbar button is pressed), the sketch and additional info (e.g. EMF, rxnFile) is transferred to my WPF application. It's much like mimicking an OLE server operation. Maybe there's an easier way to this?

ChemAxon bd13b5bd77

28-03-2011 06:55:31

To this solution we might have a predefined component:


         var editor = new ChemAxon.NET.Windows.Forms.MarvinEditorControl.MarvinSketchForm();
         if (editor.ShowAsDialog()) {
            string moleculeData = editor.MoleculeString;
         }
         chemaxon.struc.RxnMolecule rxn = (chemaxon.struc.RxnMolecule) chemaxon.formats.MolImporter.importMol(data);


This component implements the


namespace ChemAxon.NET.Base.View {
   public interface IMoleculeEditorView {
      string MoleculeFormat { get; set; }
      string MoleculeString { get; set; }
      string Title { get; set; }


      void Dispose();
      string GetValidationError();
      bool IsValid();
      bool ShowAsDialog();
   }
}


interface you can use to communicate with like an OLE.


 


Viktor


ChemAxon bd13b5bd77

28-03-2011 07:17:45

Question:


if you add a C# project into your solution and you add an interface only to your new C# module:


namespace Test {
   interface TestIFace : [email protected] {
   }
}


which does not  add anything just extends the critical one. 


And if you add an emty object implementing this TestIface from VB.NET, and you say to the intellisense to implement this iface, what routines will be added by the editor in VB.NET?


If it can add the missing methods (4 pieces) then what happens if you navigate back to the base to base by saying 'Go to Declaration' ?


 

User 1a8d11549a

28-03-2011 09:04:01

Hi Victor,


The MarvinSketchForm code was exactly what I needed! Thanks a lot for bringing this to my attention. For newbies like me it might be a great idea to add something along these lines to your NET code examples :-)


I should mention that at first the code didn't work at all, until I finally found that all projects of my solution need to target the .NET Framework 4.0, and not the more compact NET Framework 4.0 Client Profile. Ouch! Does the namespace ChemAxon.NET.Windows.Forms actually require the larger the non-client profile Framework? I somehow doubt it. If not, one might think about targeting it towards the Client Profile version in the next release to save some prerequisite overhead ...


Finally: Is there a way to change MarvinSketch options from code via MarvinSketchForm or otherwise, e.g. for switching off the default colored atom labels, or  for switching off "Show Bond on Hand"?

ChemAxon bd13b5bd77

28-03-2011 09:50:48

I do no think that adding ChemAxon.NET.Windows.Forms brings a lot more on the board. However please run some tests around it.


Let me look up a little bit how you could change the settings from code.


To be honest so far it was not a requirement since MsketcPane wrapped up by this control and form reads up the user settings as far as I know.


If the user settings take the effect then if I were you I would not worry about that too much ( it will be changed anyway by the user) except if it is not a busineess requirement from your side against your program.


Anyway, I will ask about it in Marvin team how it works, and then you can choose between your solution or the predefined MarvinSketchForm.


We will expose the settings in the next version of .NET control by next time.


 


Any succsess with vb.net and interface implementation?

User 1a8d11549a

28-03-2011 11:15:15

After having my basic problem solved by using the MarvinSketchForm route, the vb.net interface issue has become a rather theoretical one for me, and I honestly currently don't plan to spend time & effort to follow this route anymore.


And good news to hear that the settings will be exposed in the next version of the .NET control! It can help to apply initial settings beyond basic layout for new users coming e.g. from ISIS/Symyx/Accelrys Draw, so that they feel at home more quickly. I know by experience how easily users otherwise refuse a new application which doesn't out of the box feel 99% the way as the app they were used to for many years. 


Concerning .NET Framework Client Profile, just for clarifying: The .NET Framework 4.0 Client Profile is a non-optional Windows Update component since a while, i.e. it already should be part of every updated Windows Vista and Windows 7 machine. However, the full .NET Framework 4.0 is not, and any application installer needs to downlad and install it separately if not present. That's not the end of the world, but obviously it's a much swifter installation experience if this is not required. But maybe the IKVM components used internally by ChemAxon.NET.Windows.Forms require access to the additional web components contained in the full Framework, which could explain the depedency.


And a final question concerning licensing, since I'm quite convinced now about the possibilities of MarvinSketch (and the competent and reactive support!): According to the EULA, the use of MarvinSketch is free of charge, as long as it is not an integral part of an application. What does this mean for an application using the ChemAxon dll's and the separate MarvinSketch popup window as outlined in your MarvinSketch sample code, e.g. towards exchanging information for generating an internal XAML image and retrieving rxnfile string content as in my case? The users would download and install MarvinSketch (and therefore also the required dll's) separately. Would this count as an integral part of the application? Possibly that's not the right forum topic to ask about, but maybe you know about it, or you can pass me to someone who knows about it.


  

ChemAxon bd13b5bd77

28-03-2011 11:27:56

Dear John,


Once I get answer from Marvin dev. team I will notify you immediatelly about when to extend the SketchForm with chemical settings. Possibly in the next build 5.5 or 5.5.1. I have not got response yet.


I think ChemAxon.dlls are part of JChem .NET API and for any integration the license question should be discussed with other department of ChemAxon.


Please turn to Nora Lapusnyik <[email protected]>.


Viktor

User 1a8d11549a

28-03-2011 11:35:29

Ok, I'll contact your licensing. Thanks again for all of your help, Victor, I have all the required pieces together now, this was highly valuable to me!

User 1a8d11549a

30-03-2011 05:49:45

Just an observation for the MarvinSketchForm dialog: User-applied preference changes are not persisted when closing the dialog (at least on Windows 7). The next time the dialog opens all preferences are back to default. So it's even more important to make the settings available programmatically, as planned.

ChemAxon bd13b5bd77

30-03-2011 12:54:03

Yes, it seems that it is a "bug" in our component. I have fixed this for 5.5 version. It is now in alpha phase.


Coming up soon.


For the time being I will send you an ugly workaround for you, which should be eliminated once 5.5 is released.

ChemAxon bd13b5bd77

30-03-2011 17:46:37

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ChemAxon.NET.Windows.Forms.MarvinEditorControl;


namespace CustomEditor {


   /// <summary>
   /// Reflector class to extract typed hidden fields
   /// </summary>
   /// <typeparam name="T"></typeparam>
   internal class ParentField<T> {
      object _instance = null;
      string _name = string.Empty;
      System.Reflection.FieldInfo _field = null;


      private System.Reflection.FieldInfo GetField(Type type) {


         // check if we get a type at least
         if (type != null) {
            System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.SetField | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance;
            var field = type.GetField(_name, flags);
            if (field == null) {
               var fields = type.GetFields(flags);
               foreach (System.Reflection.FieldInfo anynymField in fields) {
                  if (anynymField.FieldType == typeof(T))
                     return anynymField;
               }
            }
            else {
               if (field.Name == _name) {
                  return field;
               }
            }

            // check it recursively in the base
            field = GetField(type.BaseType);
            if (field != null) {
               return field;
            }
         }
         // report that the desired field is unavailable
         throw new Exception("Field cannot be found!" + Name);
      }


      /// <summary>
      /// Constructor logic to wrap up the field we want to achieve later on
      /// </summary>
      /// <param name="chiledInstance"></param>
      /// <param name="name"></param>
      internal ParentField(object chiledInstance, string name) {
         _instance = chiledInstance;
         _name = name;
         _field = GetField(_instance.GetType());
      }
      /// <summary>
      /// name of the field we try to own here
      /// </summary>
      string Name {
         get {
            return _name;
         }
      }
      /// <summary>
      /// Get the value of the field
      /// </summary>
      internal T Value
      {
         get {
            return (T) _field.GetValue(_instance);
         }
         set{
            _field.SetValue(_instance, value);
         }
      }
   }


   public partial class Form1 : MarvinSketchForm {
      public Form1() {
         InitializeComponent();
      }


      protected override void OnFormClosing(FormClosingEventArgs e) {
         var baseEditor = new ParentField<MarvinEditorControl>(this, "editor");
         var sketcher = new ParentField<chemaxon.marvin.beans.MSketchPane>(baseEditor.Value, "_content");
         sketcher.Value.getUserSettings().save("Marvin parameters");
         base.OnFormClosing(e);
      }
   }
}

ChemAxon bd13b5bd77

30-03-2011 17:55:08

This is a temporar solution only for you, if anyone else reads this section please ignore it.


Explanation: sketcher pane is encapsulated and we do not tend to expose it via the interface either now and in the future.


What we are trying to target in the future is to collect the need from our customers and expopse it via the interface. So my workaround is to find the particular encapsulated field and trying to access it.


The code I sent you is trying to do that in two steps, for this I wrote a smarter generic class representing a field in the parent object. This ParentField is capable of finding the particular field from down to up in the inheritance tree.


The aim is to save the settings at exactly that time when the Editor form is getting closed!


What you need to do is to inherit from the MarvinSketchForm (with ok, cancel buttons) see this inheritance as Form1 : MarvinSketchForm in my code example.


 

User 1a8d11549a

30-03-2011 18:53:15

Thanks Victor, your code works very nicely! It wasn't all that urgent, but I'm happy to have it at hand until version 5.5 is released (at this stage l will of course discard this workaround).

User 1a8d11549a

31-03-2011 05:23:55

Another observation: The MarvinSketchForm dialog unexpectedly closes when pressing the ESC key and all work is lost. While this might be standard behavior of a default dialog, the ESC key is a functionality of MarvinSketch, e.g. for detaching a sticky template from the cursor. It would be good if this could beconsidered to be fixed also..

User 1a8d11549a

31-03-2011 05:46:44

Follow-up: I re-checked, and it seems that is happens just after opening the dialog. I usually had a sticky bond tearing along with the cursor, and pressing ESC there, without having clicked into the sketch area, would close the dialog. After working in the sketch area, this furtunately doen't happen again, and no work is lost. So it isn't as bad as first thought ...

ChemAxon bd13b5bd77

31-03-2011 07:22:10

Yes, that is the default behaviour of the System.Windows.Forms.Form object if the cancel button is set.
I think this has been designed in this way by Microsoft for years.


If you do not like this and as the cancel button is set in the base (MarvinSketchForm),


what you need to do is to take the constructor of your inherited form from the previous code sample:


      public Form1() {
         InitializeComponent();
         base.CancelButton = new System.Windows.Forms.Button();
      }


I think this is the clearest solution. Meaning of this line is to set the cancel event to a button, which is never showed and never clicked, it is just in the memory.


 

User 1a8d11549a

31-03-2011 07:51:45

For clarification: As mentioned above after re-checking, ESC is active BEFORE clicking inside the sketch area, but no more after, so the default behavior you referred to actually is non-existent at this stage. Again, it's not a big issue, just a slight inconsitency, and I acutally much prefer this behaviour from the purely standard one, possibly causing unwanted loss of work when pressing ESC.

ChemAxon bd13b5bd77

31-03-2011 07:56:09

Understood. Just gave you an alternative to completly eliminate the Esc working mechanism if you need.


If you apply it, your users are still capable of cancelling the modification in your applciation if they use Cancel button or 'X' on the form.


Did you manage to clarify the license issues with the marketing department?

User 1a8d11549a

31-03-2011 08:07:54

Yes, I had a very nice talk with Nora on Tuesday, and they they are thinking about possible options, but I haven't heard back so far.-  In this context: Does a user need to install the complete Marvin app to take advantage of the MarvinSketch Form dialog solution, or would it be sufficient just to distribute the required dll's with the installer?

ChemAxon bd13b5bd77

31-03-2011 08:46:56

From licence perspective normally a Marvin license is needed for using the Marvin Sketch component.
Norci will contact you re licencing and business perspective.


Technically, you can redistribute the dlls and also you can run the JChem.NET API installer containing sketcher, OLE other features. MSI packages are also available (32, 64 bit)


For more details, please visit this site:


http://www.chemaxon.com/download/marvin/for-net-developer/


 

User 1a8d11549a

31-03-2011 08:54:37

Thanks for the info.

ChemAxon bd13b5bd77

16-06-2011 14:51:40

Improved the search algorythm a little bit above in the parentField class.