Link to home
Start Free TrialLog in
Avatar of mindweaver
mindweaver

asked on

Make drawString / drawImage linkable (url/hyperlink)

Hey

Is there any way to make a drawString into a hyperlink and make it clickable?

g.drawString(lines[i], x, flexibleHeight + (i * line_height) + flexibleVectorHeight); // drawing one line from the lines-array

that is my string. and I have a gotoURL function:


      public void gotoURL(String visitURL){
        try {    
          url = new URL(visitURL);
        }
        catch(MalformedURLException e){
          System.out.println(e);
        }
      }

Now I want to assign something to that string so that it will be able to set gotURL and execute it via:

          gotoURL(urllist[i]);
          getAppletContext().showDocument(url);

in my mouse event listener. Anybody have a clue on how to solve this problem? Giving it high points because it has been bugging me for a looong time.

ASKER CERTIFIED SOLUTION
Avatar of scanadmin
scanadmin

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of scanadmin
scanadmin

found it! hope this helps, you may want to mod it a bit, uses an array of strings, you probably just want one string.

import java.awt.*;
import java.lang.reflect.Array;

public class BoxedText
{
    private Font _normalFont;
    private FontMetrics _normalFontMetrics;

    private String[] _strings ;
    private int[] _stringWidths ;
   
    private Rectangle _bounds ; // bounding rectangle of the Text
   
    private int _xTextOffset ;
    private int _yTextOffset ;

    // the gap to leave between the text and the box
    private static final int GAP = 2 ;
   
    /** Creates a new instance of BoxedText */
    public BoxedText (int x, int y, String[] strings, Font nFont,FontMetrics nFontMetrics)
    {
        // Need to clone the array to ensure we never get aliasing problems
        _strings = (String[])strings.clone ();
        _stringWidths = new int[_strings.length] ;
        _bounds = new Rectangle (0, 0, 0, 0) ;
       
        _normalFont = nFont ;
        _normalFontMetrics = nFontMetrics ;
       
        // Width calculation: default if there are no strings is the 2 gaps;
        // one at each end
        _bounds.width = 2 * GAP ;
       
       
        _stringWidths[i] = _normalFontMetrics.stringWidth (_strings[i]) ;
        _bounds.width += _stringWidths[i] ;

        // Height calculation. Again, default is 2 gaps
        _bounds.height = 2 * GAP ;
       
        // only increase it further if there is at least 1 string
        if (_strings.length > 0)
        {
            // Now need the Ascent of the normal font
            _bounds.height += _normalFontMetrics.getAscent () ;
            _bounds.height += _normalFontMetrics.getDescent () ;
        }
       
        _bounds.x = x - _bounds.width/2 ;
        _bounds.y = y - _bounds.height/2 ;
        _xTextOffset = GAP ;
        _yTextOffset = GAP + _normalFontMetrics.getAscent () ;
    }
   
    public void draw (Graphics g)
    {
        // Dangerous to assume that the colour does not have to be set
        g.setColor (Color.black) ;
        int x = _bounds.x + _xTextOffset ;
        int y ;
       
        for (int i = 0 ; i < _strings.length ; i++)
        {
            g.setFont (_normalFont) ;
            y = _bounds.y + _yTextOffset ;
           
            g.drawString (_strings[i], x, y) ;
            x += _stringWidths[i] ;
        }
        // g.setColor (Color.white) ; //makes the box invisible.
        g.drawRect (_bounds.x, _bounds.y, _bounds.width, _bounds.height) ;
    }
   
    public boolean contains (Point p)
    {
        return _bounds.contains (p) ;
    }
}
Avatar of mindweaver

ASKER

Thanks alot, I have tried the rectangle trick so I know how to draw it correctly. I'll check out your example tomorrow and see if it helps me!
I dynamicly draw more than one rectangle as this is a newsticker with several news segments. Is there a way to put my rectangles in vectors/arrays or something to check if the mouse is inside the right one? Think my brain is stuck in the wrong thinking.
Here is my code, I have stared working on the bounds thingie but just can't get it in my head how to work it out. If it's not too much trouble I would love it if you (or anyone else that feels like it) could tell me how to implement your idea. I raised the points to 500.
forgot the code:


import java.applet.*;
import java.awt.*;
import java.sql.*;
import java.lang.*;
import java.util.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
import java.net.*;
import java.awt.Point;

public class JollyTicker extends Applet implements Runnable, MouseListener, MouseMotionListener  {  // implementing the Runnable interface to be able to use the Thread object and the run() method

        String currentThread = "imageThread"; // declaring and setting a variable to hold which the current thread is
        Thread mainThread = null;  // setting the main Thread
        Thread imageThread = null; // setting the image Thread
        int width = 150;        // declaring and setting the width variable
        int height = 150;       // declaring and setting the height variable
        int x, y;               // declaring the x and y coordinates as integers
        String text;            // declaring a variable to hold our text
        String urltext;            // declaring a variable to hold our urls
        String toptext;         // declaring a variable to hold our headline text
        String fontFamily;      // declaring a variable to hold the font family
        int fontSize;           // declaring a variable to hold the font size
        Color backgroundColor;  // declaring a variable to hold the background color
        Color textColor;        // declaring a variable to hold the text color
        int pause = 2000;       // declaring and setting the pausvariable (milliseconds)
        int speed = 80;         // declaring a variable for the speed and giving it a value (milliseconds)
        String lines[];         // creating an array that will hold the text
        String headlines[];     // creating an array that will hold the headlines
        int num_lines;          // declaring a variable to hold the number of lines of text
        int num_lines_total;
        int line_height;                   // declaring a variable to hold the text line height
        int flexibleHeight = height;       // declaring and setting a variable to hold the current height of the scrolling text
        Vector newsContent = new Vector(); // creating a vector for holding our news segments (content)
        Vector newsCaption = new Vector(); // creating a vector for holding our news segments (headlines)
        Vector newsURL = new Vector();     // creating a vector for holding our news segments (URL)
        Vector flexibleVectorSizes = new Vector();
        int flexibleVectorHeight;          // declaring a variable to hold the news segment heights
        int newsGap = 40;                  // declaring and setting a variable to hold the gap between news articles
        ArrayList pauseTracker = new ArrayList(); // creating an ArrayList to hold the pause values
        int pauseValues = 30;                     // declaring a variable to hold the news segment pause values
        boolean scrollingPause = false;    // variable that holds values wether the scrolling is paused of not
        Image offlineImage;                // creating an offline image for placing our text on ( for dubblebuffering )
        Image JT_logo;
        Graphics offlineCanvas;            // creating an offline canvas for putting our offline image and it's content
        URL url = null;
        boolean m_over = false;
        int mouse_y;
        int cur_news = 0;
        int fmheight;
        String currentURL;
        int segmentSize = 0;
        int flexibleHeights = 0;
        private Rectangle _bounds ; // bounding rectangle of the Text

        public JollyTicker(){   // constructor for our JollyTicker class, leaving it emtpy
        }


        public void init() {  // method for setting all crucial values
        addMouseListener(this);        // adding mouselister to pick up mouse events
          addMouseMotionListener(this);  // adding mousemotionlistener to pick upp mouse movement events
          resize(width, height);         // setting the width and height of the applet

          try {
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // Calling the JDBC:ODBC bridge to be able to connect to our MS Access database
            Connection con = DriverManager.getConnection("jdbc:odbc:JollyTickerDatabase");  // creating a connection and reading the database via an ODBC connection made by the installer
            Statement s = con.createStatement(); // creating a java.sql.Statement
            s.execute("SELECT news_caption, news_text, news_link FROM JT_content"); // getting the our text from the database
            ResultSet rs = s.getResultSet(); // get any ResultSet that came from our query
            while ( rs.next() ) { // stepping through our data row-by-row
              newsContent.addElement(rs.getString("news_text"));  // adding all rows of textcontent into the newsContent vector
              newsCaption.addElement(rs.getString("news_caption"));  // adding all rows of textcontent into the newsContent vector
              newsURL.addElement(rs.getString("news_link"));  // adding all rows of textcontent into the newsContent vector
            }
            s.close(); // closing the Statement
            con.close(); // closing the Connection
          }
          catch (Exception e) {
            System.out.println("Error: " + e);
          }
        }

        public void paint(Graphics g){             // method for setting the textcolor and writing our text
          if (offlineImage != null) {              // checks if there is an instance of our offlineImage with content
          g.drawImage(offlineImage, 0, 0, null); // draws our image with it's content
          }
        }


        public void update(Graphics g) {

          if (offlineCanvas == null){ // first time running, creating our offline graphics canvas
            offlineImage = createImage(width, height);     // creating an offline image
            offlineCanvas = offlineImage.getGraphics();    // adding our offline image to our offline canvas
            fontFamily = "Trebuchet MS";                   // setting the font family
            fontSize = 10;                                 // setting the font size
            textColor = Color.BLACK;                       // assigning a color to the fontColor variable
            backgroundColor = Color.WHITE;                 // assigning a color to the backgroundColor variable
            offlineCanvas.setColor(backgroundColor);       // setting the background color
          }
          this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));  // changing the cursor when mouse is over the applet
          offlineCanvas.setColor(backgroundColor);      // setting the background color
          offlineCanvas.fillRect(0, 0, width, height);  // filling the screen with our canvas
          paintFrame(offlineCanvas);                    // drawing the offline frame canvas on to the screen
          g.drawImage(offlineImage, 0, 0, null);        // drawing our offline image to the screen
      }

      public void paintFrame(Graphics g) { // this lovely thing will paint it all
   
        if (currentThread == "imageThread") { // checks to see if our imageThread is running
          JT_logo = getImage(getCodeBase(), "jtlogo.gif");
          JTMediaTracker(); // Calls our mediatracker to draw the image faster
          g.drawImage(JT_logo, 0, 0, 150, 150, null); // draws the logo to the screen
        }
        else if (currentThread == "mainThread") { // checks to see if our mainThread is running
   
          g.setColor(textColor); // setting the text color
          flexibleVectorHeight = 0; // giving the flexibleVectorHeight an initial value
   
          for (int k = 0; k < newsContent.size(); k++) { // looping through the vector where we added our news content from the database

            urltext = newsURL.elementAt(k).toString();
            currentURL = urltext;
            toptext = newsCaption.elementAt(k).toString(); // assigning the values from the database->vector to my text-variable
            text = newsContent.elementAt(k).toString(); // assigning the values from the database->vector to my text-variable
           
            String lines[] = text.split("\\u005cn"); // \u005c is the hex code for the backslash (92 decimal) Splitting up the text and entering the parts into an array
   
            if (pauseTracker.size() < newsContent.size()) { // everything in this if condition only needs to be run as many times as there are entrys in the newsContent vector
              pauseTracker.add(new Integer(pauseValues)); // adds a value to the pauseTracker that will be used later when we want to pause the news scrolling
              _bounds = new Rectangle (0, 0, 0, 0) ;

              Font f = getFont(); // getting our font context
              FontMetrics fm = getFontMetrics(f); // getting out FontMetrics
              line_height = fm.getHeight(); // setting the line_height variable to the our font lineheight
              num_lines = lines.length; // setting the number of rows to the num_lines variable
              num_lines_total += num_lines; // setting number of rows total to be able to check when all news has been displayed
            }
            g.setFont(new Font(fontFamily, Font.BOLD + Font.PLAIN, fontSize)); // setting the font for the headline
            g.drawString(toptext, x,flexibleHeight + flexibleVectorHeight - line_height); // drawing one line from the lines-array
            int i;
            for (i = 0; i < lines.length; i++) { // creating a loop for drawing all of our lines
              g.setFont(new Font(fontFamily, Font.PLAIN + Font.PLAIN, fontSize)); // setting the font for the headline
              g.drawString(lines[i], x,flexibleHeight + (i * line_height) + flexibleVectorHeight); // drawing one line from the lines-array
            }
            _bounds.x = x;
            _bounds.y = flexibleHeight + flexibleVectorHeight - 10;
            _bounds.width = 145;
            _bounds.height = (num_lines * line_height + newsGap);
           
            // g.setColor (Color.white); // makes the box invisible
            g.drawRect(_bounds.x, _bounds.y, _bounds.width, _bounds.height);

            System.out.println(currentURL);
           
            flexibleVectorHeight += i * line_height + newsGap; // calculating where to enter the next news segment (below)
            pauseValues -= (num_lines * line_height + newsGap); // calculating where each news segment should pause scrolling
          }
        }
      }

      public boolean contains(Point p)
      {
          return _bounds.contains(p);

      }

        public void start(){

          if(currentThread=="mainThread"){
            if (mainThread == null) { // checks if mainThread is an instance of Thread
              mainThread = new Thread(this); // creating an instance of Thread
            }
            mainThread.start(); // starting mainThread
          } else if(currentThread=="imageThread"){
            if (imageThread == null) { // checks if mainThread is an instance of Thread
              imageThread = new Thread(this); // creating an instance of Thread
            }
            imageThread.start(); // starting mainThread
          }

        }

        public void stop() {  // when the applet is no longer visible the Thread is set to null
            mainThread = null;
            imageThread = null;
            offlineImage = null;
            offlineCanvas = null;
        }

        public void run() { // method that places our string, writes it to the front and moves it upwards

          Thread.currentThread().setPriority(Thread.MIN_PRIORITY); // lowering the priority of the thread for less interfearence

          while (Thread.currentThread() == mainThread) {  // creating a unlimited loop
            x = 5;     // setting the distance of the text from the left "wall"
            repaint(); // calls the paint-mehod

            flexibleHeight--; // decreasing the placement of our graphical object by 1 in the y-axle
            if ( (flexibleHeight + (num_lines_total * line_height)) < 0) { // checking so that the the text haven't reached the top of the applet
              try {
                Thread.sleep(pause); // pausing the news segment (halting the Thread for a certain amount of time)
              }
              catch (InterruptedException e) {
              }
              flexibleHeight = height + line_height; // resetting the vertical placement
            }

            for (int i = 0; i < pauseTracker.size(); i++) { // looping through the pauseTracker giving the "pauser" it's values
              Object pauseTrackerObj = pauseTracker.get(i); // getting the values from the pauseTracker as objects
              int pauseTrackerInt = Integer.parseInt(pauseTrackerObj.toString()); // creating a variable and converting the pauseTracker objects into integers
               if (flexibleHeight == pauseTrackerInt) { // checks if the news segments has reached the top of the applet
              try {
                Thread.sleep(1500); // pausing the news segment (halting the Thread for a certain amount of time)
              }
              catch (InterruptedException e) {
              }
              }
            }
              try {
                Thread.sleep(speed); // setting the time between repaints, which will be the speed of our scrolling text
              }
              catch (InterruptedException e) {
              }
          }

          while (Thread.currentThread() == imageThread) {  // creating a unlimited loop

            repaint();  // calling the paint-method
            try {
              Thread.sleep(2000); // setting the time between repaints, which will be the speed of our scrolling text
            }
            catch (InterruptedException e) {
            }
            stop();                       // stopping the thread
            currentThread = "mainThread"; // setting the new thread
            start();                      // starting the new thread
          }
      }

      // ************************************************************************** //
      //                           MEDIATRACKER FUNCTION                            //
      //  ------------------------------------------------------------------------- //
      //  When the image is drawn in the imageThread this MediaTracker makes sure   //
      //  the image is loaded and will be displayed imediately on the loaded and    //
      //  will be displayed imediately on the screen.                               //
      // ************************************************************************** //

      public void JTMediaTracker(){
        MediaTracker t = new MediaTracker(this);  // calling the MediaTracker method
        t.addImage(JT_logo, 0);                   // adding our image to the tracker
        try {
          t.waitForAll(); // waiting for images to load before init.
        }catch(Exception e) {}
      }

      // ************************************************************************** //
      //               MOUSELISTENER AND MOUSEMOTION LISTENER EVENTS                //
      //  ------------------------------------------------------------------------- //
      //  When the user interacts with the applet using the mouse, following events //
      //  will initialize and act as follows.                                       //
      // ************************************************************************** //

      public void mouseReleased(MouseEvent e){
          scrollingPause = false; start();  // when the mouse is released the scrolling starts
      }
      public void mousePressed(MouseEvent e){
          scrollingPause = true; stop();    // when the mouse is pressed the scrolling pauses
          //gotoURL(currentURL);
         
          System.out.println("---------------------------------------------------");
          System.out.println("mouse_y: " + mouse_y);
          System.out.println("current URL: " + currentURL);
          System.out.println("---------------------------------------------------");
          getAppletContext().showDocument(url);

         

         
          if(_bounds.contains(150,150,150,150)){
            System.out.println("contains");
          } else {currentURL="";}
      }
      public void mouseExited(MouseEvent e){
        m_over = false;
        repaint();
        System.out.println(m_over);
      }
      public void mouseEntered(MouseEvent e){
        m_over = true;
        mouse_y = e.getY();
        System.out.println(m_over);
        repaint();
        System.out.println("new y pos: "+ mouse_y);
      }
      public void mouseClicked(MouseEvent e){

      }
      public void mouseDragged(MouseEvent e){
      }
      public void mouseMoved(MouseEvent e){
        mouse_y = e.getY();
        m_over = true;
        repaint();
        System.out.println("new y pos: "+ mouse_y);

      }
     
     
      public void gotoURL(String visitURL){
        try {    
          url = new URL(visitURL);
        }
        catch(MalformedURLException e){
          System.out.println(e);
        }
      }

     
}
sorry about the code being messy, I hope you can figure enough out to be able to help me.
For this bit i would recomend you put all your links in an arraylist. Then you can get your mouse lisener to loop through the arraylist on a click calling the contains(Point p) method in the links class. In order to do this you will have to take the code that draws the links an make a new class as i dont think you have done here

class LinkBox(String text, int x, int x.... String link)....... etc

doing this enables you to call the contans method via a loop for all link objects, they you can use a getURL method like so

ArrayList myLinks = new ArrayList()

......... [populate arraylist with your links]

.........

public void mouseClicked(MouseEvent e){
             for (int x = 0; x < myLinks.size(); x++){
                  LinkBox lb = (LinkBox)myLinks.get(x);
                  if ( lb.contains( new Point(e.getX(), e.getY()) ) ){
                             url = new URL( lb.getURL() );
                  }
             }
      }


hope this helps, you have the right idea, you just have to split it up into little classes and it will make you life a lot easier..... this is the beauty of object oriented languages.





scanadmin, thanks for your followup, I have already solved it! and it works great :)

for those who are interrested I added:
first declared:

        Vector newsURL = new Vector();     // creating a vector for holding our news segments (URL)
        Point mouse_pos;                   // creating a point object that will hold the mouse position
        String currentURL;                 // declaring a variable to hold the current URL to visit when clicking on a news segment
        Rectangle _bounds ;                // creating an Rectangle object to hold the linked areaboxes

Then in my init():

_bounds = new Rectangle(0, 0, 0, 0); // creating an instance of the Rectangle object



Then in my paintFrame(Graphics g)  I added:

            _bounds.x = x;                                            // setting the x value for our linked area
            _bounds.y = flexibleHeight + flexibleVectorHeight - 10;   // setting the y value for our linked area
            _bounds.width = 145;                                      // setting the width value for our linked area
            _bounds.height = (lines.length * line_height);            // setting the height value for our linked area

           if(mouse_over){                                   // checks wether the mouse is over the applet or not
             if (contains(mouse_pos)) {                      // checks wether the mouse is located within our specified bounds (rectangle)
               currentURL = newsURL.elementAt(k).toString(); // setting the currentURL variable with the url belonging to the current news segment
               gotoURL(currentURL);                          // adding the currentURL to our URL object wich will later be executed in the mousePressed method
             }
           }

(mouse over variable changes in mouseEntered and mouseExited)

And then as follows:

      public void gotoURL(String visitURL){
        try {    
          url = new URL(visitURL);  // creating an instance of our URL object and setting the input url
        }
        catch(MalformedURLException e){
          System.out.println(e);
        }
        return;
      }

And the events:

      public void mousePressed(MouseEvent e){
         
          getAppletContext().showDocument(url); // redirects the browser to the URL referring to the clicked newssegment
      }
      public void mouseExited(MouseEvent e){
        scrollingPause = false; start();  // when the mouse is released the scrolling starts
        mouse_over = false; // telling the application that the mouse has left the applet area
      }
      public void mouseEntered(MouseEvent e){
        scrollingPause = true; stop();        // when the mouse is pressed the scrolling pauses
        mouse_over = true;          // telling the application that the mouse has entered the applet area
        mouse_pos = e.getPoint();   // setting the mouse Point value (x+y-position) where the mouse enters the applet area
      }
      public void mouseClicked(MouseEvent e){

      }
      public void mouseDragged(MouseEvent e){
      }
      public void mouseMoved(MouseEvent e){
        mouse_pos = e.getPoint(); // setting the mouse Point value (x+y-position) when the mouse is moved
        mouse_over = true;        // telling the application that the mouse is over the applet area
      }

There :) maybe not the best coding but it works great and I'm happy :)