Solved

Make drawString / drawImage linkable (url/hyperlink)

Posted on 2004-10-10
9
449 Views
Last Modified: 2012-05-05
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.

0
Comment
Question by:mindweaver
  • 6
  • 3
9 Comments
 
LVL 1

Accepted Solution

by:
scanadmin earned 500 total points
ID: 12271856
Had a similar problem to tackle, and its not too bad to do. Firstly what you have to do is create an invisible rectangle around your string. Setting the box XY to the same as that of the string, then using the font metrics class you can use getStingWidth(String s) and getAscent() to add on the height and width of the string. You can then call the contains(Point P) method of the invisible box to see if you clicked on the text. Then get it to invoke the URL code.

I have sample code somewhere, will post it if i find it


hope this helps
0
 
LVL 1

Expert Comment

by:scanadmin
ID: 12271879
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) ;
    }
}
0
 

Author Comment

by:mindweaver
ID: 12272660
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!
0
 

Author Comment

by:mindweaver
ID: 12275107
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.
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 

Author Comment

by:mindweaver
ID: 12275208
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.
0
 

Author Comment

by:mindweaver
ID: 12275212
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);
        }
      }

     
}
0
 

Author Comment

by:mindweaver
ID: 12275314
sorry about the code being messy, I hope you can figure enough out to be able to help me.
0
 
LVL 1

Expert Comment

by:scanadmin
ID: 12278801
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.





0
 

Author Comment

by:mindweaver
ID: 12279619
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 :)

0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Suggested Solutions

This article is meant to give a basic understanding of how to use R Sweave as a way to merge LaTeX and R code seamlessly into one presentable document.
Whether you’re a college noob or a soon-to-be pro, these tips are sure to help you in your journey to becoming a programming ninja and stand out from the crowd.
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now