|
-
Mar 25th, 2005, 01:01 PM
#1
Thread Starter
Frenzied Member
How would you do this?
How would you put a scrolling message on your application with a seperate thread, sort of like an advertisment?
-
Mar 25th, 2005, 02:44 PM
#2
Thread Starter
Frenzied Member
Re: How would you do this?
Is it just something with drawString, and then the x value would decrease each round of the thread?
-
Mar 25th, 2005, 10:13 PM
#3
Thread Starter
Frenzied Member
Re: How would you do this?
-
Apr 15th, 2005, 05:14 PM
#4
Addicted Member
Re: How would you do this?
how did you do it? i need to add something similair to a splash screen.....
Some code would be nice if you have a snippet..
Andy
-
Apr 15th, 2005, 06:54 PM
#5
Thread Starter
Frenzied Member
Re: How would you do this?
Well, there is two different ways you can do it. You can use a Timer Object, or you can use simple Threads. I used a thread. First I started with a Label with some starting text. I created the thread, and this is what My run() method looks like:
Code:
public void run()
{
/* we start a while loop, that will loop will it is true, and since
* nothing ever makes it false it never stops. So no matter how long the
* program is run, it will always be going.
*/
while (true)
{
/* Since we are working with threads, we must put our operations in a try
* catch clause so that we can trap errors that will possibly arise.
*/
try
{
/* get the old text, which is just the text on the JLabel at this
* moment. We will need this later.
*/
String oldText = adLabel.getText();
/* create a new String, that will perform some operations on the old text
* and then set the text of the JLabel to the new text. The first part of this
* (substring(0)), takes one parameter, this parameter is the starting index of the
* string, and then grabs everything else. Again, index's start at index 0, so this
* is cutting the string off by one. So, if the text is "text", then the first part
* cuts it down to "ext". Then you have the concatenating operater(+) that adds text
* to the preceding string. The third part, oldText.substring(0,1), has two parameters,
* the beginning index, and the ending index. We specify 0, and 1. This basicly means it
* grabs the first character of the old text. So, if we had "text", as the label, then it
* would get the "t" out of text since it is the first letter. Then that is added to the\
* first operation(where we got "ext"....This ends up putting the text as "extt", but of course
* if you had spaces after the message, it would be much clearer("ext t", then "xt te", then
* "t tex", and last " text", and it would loop from there.
*/
StringBuffer newText = StringBuffer.append(oldText.substring(1) + oldText.substring(0, 1));
//set the text of the label to the new text
adLabel.setText(newText);
/* The thread class has a method called sleep(). This method will pause the thread for a given
* amount of time in milliseconds. We specify 250, but this can be changed. You put the time
* in milliseconds as the parameter for the method.
*/
Thread.sleep(250);
}
/* If you use a thread, you must catch the interrupted exception. This exception
* will occur if the thread is interrputed in anyway, hence the name interrupted
* exception. If this exception occurs, we don't want to continue.
*/
catch (InterruptedException e)
{
/* Since we don't want to continue if this exception occurs, we make a call to
* the stop method. This wll stop the thread all together.
*/
stop();
}
}
}
I used a StringBuffer to keep track of the text so I wouldn't use so much Stack memory.
By the way, if you don't mind me asking: How do you create a spalsh screen in java?
-
Apr 16th, 2005, 04:06 AM
#6
Addicted Member
Re: How would you do this?
so it actually scrolls left to right, i though you wanted something that scrolled upwards, like credits on a film?
cool tho, cheers..
-
Apr 16th, 2005, 06:53 AM
#7
Thread Starter
Frenzied Member
Re: How would you do this?
Actually I do. I never could figure out how though. If you know, please tell.
-
Apr 16th, 2005, 07:15 AM
#8
Addicted Member
Re: How would you do this?
Here is some code for a splash screen for you, it basically renders a picture behind the scenes but allows you to add some splash content to the glass pane, i use it and it works pretty well, allowing us to change the splash screen with different locales...
If you wanted, and i like i will add is the scrolling section, i have a few ideas onhow to get a scrolling affect, i'll post my code when i have it working...
Code:
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
/**
* This is a Splash Screen that will stay up for as long as you want it
* to, with start an stop methods, that can optionally use a set
* minumum time that will prolong the splash screen even when the
* stop method is called.
* @author ad
*/
public class SplashScreen {
/**
* Thread that hods our splash screen.
*/
// private Thread t;
/**
* The Window
*/
JWindow window;
/**
* The Mimimum Time we should be shown.
*/
private int minimumTime;
/**
* The Time we were started.
*/
private long startTime;
/**
* Time Action Listener.
*/
private ActionListener listener;
private Component parent;
/**
* Start a Splash Screen
* @param icon
*/
public SplashScreen(final Image icon){
this(icon, 0, null);
}
/**
* Start a Splash Screen
* @param icon
* @param glass - the glass pane content
*/
public SplashScreen(final Image icon, JComponent glass){
this(icon, 0, glass);
}
/**
* Start a splash screen with a minumum startup time.
* @param icon
* @param minimumTime
* @param glass - this is the glass pain extras
*/
public SplashScreen(final Image icon, int minimumTime, JComponent glass){
this.minimumTime = minimumTime;
this.init(icon);
this.setGlassPaneContent(glass);
}
/**
* This will make the Splash screen a little heavier,
* but will allow the addition of JComponenets on
* the splash screen.
* @param component
*/
public void setGlassPaneContent(JComponent component){
if(component != null){
JPanel glassPane = new JPanel();
glassPane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
glassPane.setOpaque(false);
glassPane.setLayout(new GridLayout(1,1));
glassPane.add(component);
this.window.setGlassPane(glassPane);
this.window.getGlassPane().setVisible(true);
}
}
/**
* Initialise the Splash Screen
* @param icon
*/
private void init(final Image icon){
this.window = new JWindow(){
// /**
// * @see java.awt.Container#paintComponents(java.awt.Graphics)
// */
// public void paint(Graphics g) {
//// Dimension d = this.getPreferredSize();
//// g.drawImage(icon, 1,1, null);
// super.paint(g);
// }
};
/**
* Set the Size to the Image Size
*/
this.window.setSize(icon.getWidth(null) + 2, icon.getHeight(null) + 2);
JLabel label = new JLabel();
label.setIcon(new ImageIcon(icon));
label.setOpaque(false);
label.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
this.window.getContentPane().setLayout(new GridLayout(1,1));
this.window.getContentPane().add(label);
/**
* Centre the window on the screen.
*/
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension d = this.window.getSize();
this.window.setLocation(screenSize.width/2 - (d.width/2),
screenSize.height/2 - (d.height/2));
//
// Runnable r = new Runnable(){
// public void run() {
// window.show();
// }
// };
// this.t = new Thread(r, "Studio Splash Worker");
this.listener = new SplashActionListener();
}
/**
* Start the Splash Screen
*/
public void start(){
SwingUtilities.invokeLater(new Runnable(){
public void run() {
SplashScreen.this.window.show();
}
});
this.startTime = System.currentTimeMillis();
this.window.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
/***
* Stop the Splash Screen
*/
public void stop(){
/**
* Check the Startup time.
*/
if((System.currentTimeMillis()) >= (this.startTime + this.minimumTime)){
this.window.dispose();
this.window.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}else{
Timer t = new Timer((int) ((this.startTime + this.minimumTime) - System.currentTimeMillis()), this.listener);
t.setRepeats(false);
t.start();
// Invoke this block in the swing thread, or it deadlocks on Linux
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SplashScreen.this.window.toFront();
SplashScreen.this.window.requestFocus();
}
});
}
}
/**
* Actually Force a stop
*/
public void forceStop(){
SwingUtilities.invokeLater(new Runnable(){
public void run() {
SplashScreen.this.window.setVisible(false);
SplashScreen.this.window.dispose();
SplashScreen.this.window.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
});
}
private class SplashActionListener implements ActionListener{
/**
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
forceStop();
}
}
/**
* Set the panre fo the Splash.
* @param parent - the parent of the splash screen
*/
public void setParent(Component parent) {
this.parent = parent;
}
-
Apr 16th, 2005, 08:19 AM
#9
Addicted Member
Re: How would you do this?
Ok here is a crude vertical scrolling component: and its my first attempt so might need some tweaking before its robust enough to do exaclty what you want it to do:
Code:
/**
* @author ad
*/
public class ScrollingTextComponent extends JComponent implements ActionListener{
private String[] text;
private Timer t;
int start = 80;
/**
* Create a new Scrolling Text Component
* Either Up for Left.
*/
public ScrollingTextComponent(String[] text) {
this.text = text;
this.t = new Timer(20, this);
this.t.start();
}
/**
* paint
* @see javax.swing.JComponent#paint(java.awt.Graphics)
*/
public void paint(Graphics g) {
FontMetrics fm = g.getFontMetrics();
int yLocation = this.start + fm.getHeight();
int stopCount = 0;
for(int i = 0; i < this.text.length; i++) {
if(yLocation > 0) {
g.drawString(this.text[i], 0, yLocation);
}else {
stopCount++;
}
yLocation += + fm.getHeight();
}
if(stopCount == this.text.length){
this.t.stop();
System.out.println("Stopped");
}
this.start--;
}
/**
* actionPerformed
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
/**
* Force a Repaint.
*/
this.repaint();
}
}
basically it starts a timer, scrolls the text, when it dissapears it stops the timer, there is no reason why you' couldn;t get it to repeat again and again....
Let me know if its what you wanted and we can improve on it...
Andy
-
Apr 16th, 2005, 01:48 PM
#10
Thread Starter
Frenzied Member
Re: How would you do this?
Did you get the scrolling text to compile? I added the import statements, but I can't get the class to compile. The code looks fine, but for some reason I'm getting some errors. Am I missing something?
-
Apr 16th, 2005, 02:00 PM
#11
Addicted Member
Re: How would you do this?
yeah it compiled and ran for me: here is the code again:
Code:
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.Timer;
/**
* @author ad
*/
public class ScrollingTextComponent extends JComponent implements ActionListener{
private String[] text;
private Timer t;
int start = 80;
/**
* Create a new Scrolling Text Component
* Either Up for Left.
*/
public ScrollingTextComponent(String[] text) {
this.text = text;
this.t = new Timer(20, this);
this.t.start();
}
/**
* paint
* @see javax.swing.JComponent#paint(java.awt.Graphics)
*/
public void paint(Graphics g) {
FontMetrics fm = g.getFontMetrics();
int yLocation = this.start + fm.getHeight();
int stopCount = 0;
for(int i = 0; i < this.text.length; i++) {
if(yLocation > 0) {
g.drawString(this.text[i], 0, yLocation);
}else {
stopCount++;
}
yLocation += + fm.getHeight();
}
if(stopCount == this.text.length){
this.t.stop();
System.out.println("Stopped");
}
this.start--;
}
/**
* actionPerformed
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
/**
* Force a Repaint.
*/
this.repaint();
}
}
-
Apr 16th, 2005, 02:35 PM
#12
Thread Starter
Frenzied Member
Re: How would you do this?
That was really cool. It was a lot smoother than my horzontal scrolling text. I wonder if me using a JLabel to contiously show the text made it "laggy"...
-
Apr 16th, 2005, 02:49 PM
#13
Addicted Member
Re: How would you do this?
well that little thing is no more sophisticated than a Jlabel, the Jlabel apprach might have been a little jerky, or appear jerky because you are adding and removing entire letters, where as we are merely moving the entire text pixel by pixel, therrfore making it seem smooth..
How to use it, well set the preffered size, and chuck it in a panel, its all ready threaded, thats what the timer does for us, it invokes a repaint in the swing thread so the repaint will be simply done just like in any of your other JComponents etc.. it also stop painting once everything is off the screen so it dosen't add any real overhead...
we could make it scroll in any direction just by taking a flag and altering either the X or Y axis...
Any other features you want?
-
Apr 16th, 2005, 03:02 PM
#14
Thread Starter
Frenzied Member
Re: How would you do this?
 Originally Posted by Andy_Hollywood
Any other features you want?
I really can't think of any, other than allowing an image to scroll right below the text.
I think I'm going to try making it run continiously, because I want to see how repainting over and over would compare to choping off characters.
-
Apr 16th, 2005, 03:07 PM
#15
Addicted Member
Re: How would you do this?
to make it repeat you can simply change the termination section, where it terminates the timer you could get it to simply reset the start coordinate.
To make it paint an image simply use the g.drawImage(image, x, y, null)
you'll just have to decide where you want the image painted....
-
Apr 16th, 2005, 03:15 PM
#16
Addicted Member
Re: How would you do this?
I've added the looping... the image thing is easy enough, i just don't have an image handy to try out, but you can see where i'd add it...
Code:
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.Timer;
/**
* @author ad
*/
public class ScrollingTextComponent extends JComponent implements ActionListener{
private String[] text;
private Timer t;
int start = 80;
private boolean firstTime = true;
/**
* Create a new Scrolling Text Component
* Either Up for Left.
*/
public ScrollingTextComponent(String[] text) {
this.text = text;
this.t = new Timer(20, this);
this.t.start();
}
/**
* paint
* @see javax.swing.JComponent#paint(java.awt.Graphics)
*/
public void paint(Graphics g) {
if(this.firstTime) {
this.start = g.getClipBounds().height;
this.firstTime = false;
}
FontMetrics fm = g.getFontMetrics();
int yLocation = this.start + fm.getHeight();
int stopCount = 0;
for(int i = 0; i < this.text.length; i++) {
if(yLocation > 0) {
g.drawString(this.text[i], 0, yLocation);
}else {
stopCount++;
}
yLocation += + fm.getHeight();
}
//g.drawImage(this.image, 0, y, null);
if(stopCount == this.text.length){
this.start = g.getClipBounds().height;
}
this.start--;
}
/**
* actionPerformed
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
/**
* Force a Repaint.
*/
this.repaint();
}
}
-
Apr 17th, 2005, 02:40 PM
#17
Junior Member
Re: How would you do this?
Hi guys!
to use this code do I have to put it in a separates class and then call it from my main frame? Thats what I'm trying to do but there is an error...
My package is named "test" and the class "ScrollingTextComponent"
This is what I do in the main frame to call it:
Code:
String laString [] = {"text here","text here","text here"};
ScrollingTextComponent laTelephone = new ScrollingTextcomponent (laString);
I underlined the error = "cannot resolve symbol: class ScrollingTextComponent in class tests.Frame1"
If you can't help me with that can you send me this already built program so i could find my mistake.
Thanks
-
Apr 17th, 2005, 02:49 PM
#18
Addicted Member
Re: How would you do this?
you need to copy the SrollingText thingy into a seperate class called ScrollingTextComponent
then in your main class you can simply call it, there shouldn't be any issues with it not compiliing as a couple of us have managed it, if you can paste all your code then it might highlight other problems we can look at...
alternaitvly add a main method to the scrolling text component, and use it like that....
-
Apr 17th, 2005, 03:34 PM
#19
Junior Member
Re: How would you do this?
Ok now I can create a new object of ScrollingTextComponent but how does it works? I dont know what to add there and i dont know if this is the way i should call it:
Code:
String laString [] = {"messsage","here"};
ScrollingTextComponent laTest = new ScrollingTextComponent(laString);
laTest.paint(what do i put here?);
laTest.actionPerformed(what do i put here?);
I'm sorry but I just wanna learn java faster than my java course teacher explains it but that's very hard to understand...
thanks
-
Apr 17th, 2005, 03:41 PM
#20
Addicted Member
Re: How would you do this?
Ok create a class file called ScrollingTextComponent , and paste the code below into it, it should at least compile and show you how it works.
Its a JComponent, so a lightweight Java Swing UI Component, that makes use of a Swing Timer, this is a timer that is fired in the swing thread so the repaints won't make a mess of your user interface by giving judery repaints etc....,
if you have a more specific question then let me know
Andy
Code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
/**
* @author ad
*/
public class ScrollingTextComponent extends JComponent implements ActionListener{
private String[] text;
private Timer t;
int start = 80;
private boolean firstTime = true;
/**
* Create a new Scrolling Text Component
* Either Up for Left.
*/
public ScrollingTextComponent(String[] text) {
this.text = text;
this.t = new Timer(20, this);
this.t.start();
}
/**
* paint
* @see javax.swing.JComponent#paint(java.awt.Graphics)
*/
public void paint(Graphics g) {
if(this.firstTime) {
this.start = g.getClipBounds().height;
this.firstTime = false;
}
FontMetrics fm = g.getFontMetrics();
int yLocation = this.start + fm.getHeight();
int stopCount = 0;
for(int i = 0; i < this.text.length; i++) {
if(yLocation > 0) {
g.drawString(this.text[i], 0, yLocation);
}else {
stopCount++;
}
yLocation += + fm.getHeight();
}
//g.drawImage(this.image, 0, y, null);
if(stopCount == this.text.length){
this.start = g.getClipBounds().height;
}
this.start--;
}
/**
* actionPerformed
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
/**
* Force a Repaint.
*/
this.repaint();
}
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(640,480));
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(new ScrollingTextComponent(new String[] {"Andrew", "Peter", "Dunn"}));
frame.show();
}
}
-
Apr 17th, 2005, 06:31 PM
#21
Junior Member
Re: How would you do this?
Hi
I'll send you my project so you would be able to see my mistake... it compiles but don't do anything... thats the way my teacher told me to use class.
My project
Thanks to help me with that you are really nice
-
Apr 17th, 2005, 07:24 PM
#22
Thread Starter
Frenzied Member
Re: How would you do this?
you never add Andy's Scrolling Component to a container
-
Apr 17th, 2005, 07:25 PM
#23
Thread Starter
Frenzied Member
Re: How would you do this?
Here was my test class(ver simple):
Code:
import java.awt.*;
import javax.swing.*;
public class TestScrollingComponent extends JFrame
{
public TestScrollingComponent()
{
String[] names = {"Bob","Joe", "Billy"};
ScrollingTextComponent stc = new ScrollingTextComponent(names);
Container content = getContentPane();
content.add(stc);
setSize(300,300);
setContentPane(content);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args)
{
TestScrollingComponent tsc = new TestScrollingComponent();
}
}
-
Apr 17th, 2005, 07:46 PM
#24
Junior Member
Re: How would you do this?
I'm sorry but i dont understand how this works... i didn't even know i had to add the scrolling component to a container...
The best way to explain it to me would be to take my project and make it work so i could see what's wrong cause i don't know where to call what...
sorry for that and thanks for helping me!
-
Apr 18th, 2005, 03:53 AM
#25
Addicted Member
Re: How would you do this?
you managed to add a Jbutton to your frame, you add the scrolling text component inexactly the same way, then you change your action listener on your Jbutton to change the text in the scrolling text pane....
as a hack you could change your jbutton1_actionPerformed code to look like this:
Code:
void jButton1_actionPerformed(ActionEvent e)
{
String laString [] = {"message","here"};
ScrollingTextComponent laTest = new ScrollingTextComponent(laString);
this.getContentPane().add(laTest, BorderLayout.CENTER);
}
-
Apr 18th, 2005, 12:43 PM
#26
Junior Member
Re: How would you do this?
Ok now everything works except that when i run the project I have an error:
java.lang.StackOverflowError
it seems thatthe error comes from my jScrollPanel
I added it in the center of the form and pasted the code in the button so I really don't know what dosen't work...
Edit: i finally fixed it but nothing happens when i play the buton...
Re-dit : I fixed it too... my app's window was too small to see the text
thanks System_Error and Andy! You are really cool guys because you took the time to explain it and help me and i appreciate it very much (sorry for mistakes I'm french...)
Last edited by lemenz70; Apr 18th, 2005 at 01:04 PM.
William
-
Apr 18th, 2005, 01:52 PM
#27
Junior Member
Re: How would you do this?
hum... only one last problem...
my project
when i click the button to start scrolling nothing happens and i have to resize the window to make it run...
-
Apr 18th, 2005, 05:46 PM
#28
Addicted Member
Re: How would you do this?
ok, well this is a common problem with swing, its basically means that the layout manager isn't telling the container that it needs to revalidate itself with the new components....
you can however force this, you can call this.getContentPane().revalidate()
or you can call this.getContentPane().repaint()
both of which should tell the frame to repaint its content....
Hope it works now
Andy
-
Apr 18th, 2005, 06:16 PM
#29
Junior Member
Re: How would you do this?
where am I supposed to add the revalidate or repaint in this class?
Code:
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.Timer;
/**
* @author ad
*/
public class ScrollingTextComponent extends JComponent implements ActionListener{
private String[] text;
private Timer t;
int start = 80;
private boolean firstTime = true;
/**
* Create a new Scrolling Text Component
* Either Up for Left.
*/
public ScrollingTextComponent(String[] text) {
this.text = text;
this.t = new Timer(20, this);
this.t.start();
}
/**
* paint
* @see javax.swing.JComponent#paint(java.awt.Graphics)
*/
public void paint(Graphics g) {
if(this.firstTime) {
this.start = g.getClipBounds().height;
this.firstTime = false;
}
FontMetrics fm = g.getFontMetrics();
int yLocation = this.start + fm.getHeight();
int stopCount = 0;
for(int i = 0; i < this.text.length; i++) {
if(yLocation > 0) {
g.drawString(this.text[i], 0, yLocation);
}else {
stopCount++;
}
yLocation += + fm.getHeight();
}
//g.drawImage(this.image, 0, y, null);
if(stopCount == this.text.length){
this.start = g.getClipBounds().height;
}
this.start--;
}
/**
* actionPerformed
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
/**
* Force a Repaint.
*/
this.repaint();
}
}
thanks
Edit: Fixed! I had to add a revalidate there:
Code:
public void actionPerformed(ActionEvent e) {
/**
* Force a Repaint.
*/
this.repaint();
this.revalidate();
}
I finally made it thanks for your help!
Last edited by lemenz70; Apr 18th, 2005 at 06:23 PM.
William
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|