I have 4 versions, all have Source code and Application only downloads.
============================================
Updated to v1.4. Appearance changed, new improvements and bugfixes (See History at bottom for changes).
I hope you'll enjoy this hopefully Final version!
Introduction
Having a few more months of C# hobby-experience by trial and error and some new updates for this NFO Viewer, I once again updated this article. I'm running Windows 7 Ultimate x64, .NET 4.5 and I use Microsoft Visual Studio 2010.
This application has a custom 'Form
', Functions to close application and mute music, custom icon, picture that goes to a website if you click it and the main thing is the richTextBox
. In this box I will load the NFO file (text), which will be presented in custom colors, scrolls down automatically and loops, and a last thing: you can't interact with the text. It has to be presented like the end credits of a movie!
Using this article you can pick any part of code to create your own viewer or use the source to create a custom Viewer of the one provided here.
Background
I had a lot of NFO files, which I had to set 'open with notepad' to show them. Notepad doesn't show all correct symbols by default and doesn't position everything in the right place. Eventually I got some NFO Viewer samples that ran instantly and had a lot of custom things. I wanted that too, but couldn't change those files. So I decided to create them myself!
The Application + Options
Since this is a new update, some buttons/functions are different. I'll leave the old options as is, so people can still use those as well. Changes since 1.3: No close button (2) anymore (press Escape instead), Test Speedbuttons removed (7), changed speed options (1x +, 1x - instead of both 2x).
Picture 'Argaï NFO Viewer v1.1'
Picture 'Argaï NFO Viewer v1.3'
Picture 'Argaï NFO Viewer v1.4 Final' (Full image from below)
The above application contains the following parts:
- The mainframe (Windows
Form
, without border);
I've used a big picture and set the Transparency
option to White, to remove all around the actual picture.
With a small piece of code, you can make the picture drag the whole application around.
A Button
(X) to close the application once you run it;
- A
checkBox
which will pause (mute) the music (mod format[.it/.xm/.s3m/.mod]) when it is unchecked;
- (Left side) A
pictureBox
that you can click on. It will open the default user's webbrowser and go to my link;
- The most important one for this app: The
richTextBox
!
This opens a specified .nfo file, converts it before presenting, load all the text and uses my edited autoscroll code to keep the text going up with a specific speed all the time. When it reaches the end, it will go back to the start and loop the scrolling. I didn't want a scroller, so I decided to 'hide' it. I also disabled all possible interactions with it.
- Another
pictureBox
, that is disabled. This means you can't interact with any event, but you can click on it and drag the application around, like the image of the 'form'.
Extra
Buttons
/KeyPress
Events for Speed Options: Pause, Slower, Faster {Limited}
- Custom
Icon
.
PictureBox
as Button
(Click Event) that opens 'About' Window.
- Music (mod format) in background that runs with application. [Needs an external Player]
- Additional Settings [Form Name, process name/description etc.]
- ToolTips [Popups with text info when mouse Holds on active Form Control]
Using the code
NOTE: As I've changed a lot in v1.4, not all code will be placed in this article. If you want to check some specific code, use the provided source code.
Let's try to explain how to make those individual parts with the specific options I wanted. You can change whatever you want to your own liking, but I wanted to create it this way and it was hard to find around the internet. At first, my application has imported all that's stated below:
using System; using System.Diagnostics; using System.Drawing; using System.Windows.Forms; using IrrKlang; .
using System.Reflection; using System.Runtime.InteropServices; using System.IO; using Un4seen.Bass;
1) The FORM [MAINFRAME]
Form
properties:
Backgroundimage
: to create the custom picture form.
BackgroundImageLayout
: None (make your white area of the picture big enough, don't repeat the image).
DoubleBuffered
: True, this prevents the application from flickering when dragging out of screen.
Icon
: Chose the icon for the application WHEN IT IS RUNNING (format .ico), not for the .exe itself. If you want the white to be transparent, use some software that can delete the unwanted are and save it as a transparent image (e.g. Paint.net). I used http://converticon.com/ to create the icon of my image.
Size
: you can manually set your size here, but in your Design View you can change it by dragging the borders.
StartPosition
: CenterScreen, this will open the application in the center of your screen.
Text
: Here you can set the text you want to appear above the Taskbar Icon of the running application.
TransparencyKey
: White, depends on the background color you want to remove of your selected picture.
We want to be able to move around our program.
To do this, create 2 new Events for the form and name them wisely, or double click the field and use the default names. In my application I always use the default ones.
In the Properties window, select the lightning icon (Events).
MouseDown
: Form1_MouseDown
MouseMove
: Form1_MouseMove
This will create two new methods to do something when these events happen on your picture (form). Add the following code to the methods in your form:
public Point mouse_offset;
private void Form1_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
mouse_offset = new Point(-e.X, -e.Y);
}
private void Form1_MouseMove(object sender,
System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point mousePos = Control.MousePosition;
mousePos.Offset(mouse_offset.X, mouse_offset.Y);
Location = mousePos;
}
}
There was a 'bug', if users pressed Arrow Keys, they would enter the richTextBox
(focus changes) and using the Arrow Keys and PageUp/Pagedown Keys they could navigate in it. I've searched and found working code to disable this. I also added the Escape key function here, as Escape is a Command key. Now you can Close the application by pressing Escape when the application is active.
In the Form_Load( )
Event, add:
foreach (Control control in this.Controls)
{
control.PreviewKeyDown += new PreviewKeyDownEventHandler(control_PreviewKeyDown);
}
Outside of this Event, add a method with following code:
void control_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{ if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
{ e.IsInputKey = true; }
if (e.KeyCode == Keys.Escape)
{ this.Close(); }
}
When this code is added, you won't be able to switch from the Form
to the richTextBox
using arrow Keys.
I also added a Fade Effect of music and app when the application closes.
This effect is triggered when the application gets a message that it needs to close.
The following code handles the effect of the appearance, and also fades the music with it. I used timers to fade away with different speeds. You can combine it and change speed if it fits, do as you want.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (this.Opacity > 0.01f)
{
e.Cancel = true;
Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_GVOL_MUSIC, 7000);
AppFadeTimer.Interval = 33;
VolFadeTimer.Interval = 10;
AppFadeTimer.Enabled = true;
VolFadeTimer.Enabled = true;
}
else
{ AppFadeTimer.Enabled = false; VolFadeTimer.Enabled = false; }
}
private void AppFadeTimer_Tick(object sender, EventArgs e)
{
if (this.Opacity > 0.01)
{ this.Opacity = this.Opacity - 0.01f; }
else
{
this.Close();
}
}
private void VolFadeTimer_Tick(object sender, EventArgs e)
{ vol = vol - 26; Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_GVOL_MUSIC, vol);}
As I make different app designs and versions, this may differ a lot, but it works.
2) The BUTTON [Close Application]
Button
Properties:
Text
: Change it to something that says: 'close me'.
Cursor
: I changed this to Hand, so you can better see it's clickable.
BackColor
and ForeColor
: Change the color style of button and text.
Size
and Location
: Drag around and resize in Design mode, or type the numbers.
We want to be able to close our program with a X-Button.
In Design Mode, add a Button
from the Toolbox, change the Property T
ext
to 'X' or 'Close' and size it to your liking. Add the Event Click
: 'button1_Click'. This will create a method for the Event to do something when the user presses the button.
Use the following code to close the application:
private void button1_Click(object sender, System.EventArgs e)
{
this.Close();
}
3) The CHECKBOX [Pause Music]
checkBox
Properties:
BackColor
: I've set this one Transparent, to see only the box, and the text has no white background then.
Checked
: I want my music ON default, so this one is True
when the application starts.
CheckState
: I want a check in my box, you can also disable the box (gray), but here it's active: Checked
.
Cursor
: Hand.
ForeColor
: LawnGreen in my example, or change it to any color you want.
Text
: Type the text that will be next to the checkBox
, in my case: Music?
Size
and Location
: Drag around and resize in Design mode, or type the numbers.
We want to be able to mute the music (pause) with a checkBox
.
In Design Mode, add a checkBox
to the form. Change the properties like the example above or to your own desire. Now we go set the checkBox
' event. We simulate that people turn of our check, to disable the music. Add the Event CheckChanged
: checkBox2_CheckedChange. Now you have the method for this event.
Add the code to pause or stop the music. In my case, I use irrKlang modplayer BASS to play the mod music files. To see how I implemented this, see 10) Music (.it format) To pause this music in irrKlang BASS, add the following code in the checkBox2_CheckChange
method:
private void checkBox2_CheckedChange(object sender, EventArgs e)
{
CheckState state = checkBox2.CheckState; if (state == CheckState.Checked) {
engine.SetAllSoundsPaused(false); }
else {
engine.SetAllSoundsPaused(true); }
}
private void checkBox2_CheckedChange(object sender, EventArgs e)
{
CheckState state = checkBox2.CheckState;
if (state == CheckState.Checked)
{ Bass.BASS_Start(); }
else
{ Bass.BASS_Pause(); }
}
4) The PICTUREBOX [Clickable]
pictureBox
Properties:
BackgroundImage
: Select the image you want to show.
BorderStyle
: I changed this to FixedSingle; seperate the dark image from the black richTextBox background.
Cursor
: I changed this to AppStarting (just for fun, to show you can click).
Size
and Location
: Drag around and resize in Design mode, or type the numbers.
We want to be able to go to a website by clicking on an image. Besides, don't pick Internet Explorer, but the default browser of the client system. In Design Mode, add a pictureBox
to the form. Change the Properties like the example above or to your own desire. Now we add the Event from the Properties' Event window: Click
, e.g. pictureBox1_Click.
In the method that we just created add:
private void pictureBox1_Click(object sender, EventArgs e)
{
Process myProcess = new Process();
{
myProcess.StartInfo.UseShellExecute = true; myProcess.StartInfo.FileName = "http://tehparadox.com/forum/f73/arga-prophecy-2001-dutch-2631589/";
myProcess.Start(); }
}
It's also nice to put ToolTips on PictureBox
or other Controls,
so people know what it'll do or where it goes to.
Above and in the Main Form Constructor add:
System.Windows.Forms.ToolTip ToolTip1 = new System.Windows.Forms.ToolTip();
public Form1()
{
ToolTip1.InitialDelay = 1200;
ToolTip1.SetToolTip(pictureBox1, "Go to: Dutch Argaï Project Forum!");
ToolTip1.SetToolTip(buttonQ, "Info");
}
5) The RICHTEXTBOX [Autoscroll locked NFO viewer]
richTextBox
properties:
BackColor
: In my example set to MenuText (black).
BorderStyle
: None, as I want to cut of any edges and the scrollbar in my scroll.
Cursor
: default is IBeam, but I don't want to select text! Set Arrow or Default (pointer).
DetectUrls
: False, I just want to present the text and I have ASCii art which contains invalid 'links'...
Font
: If you use ASCii art, this one is important, there are just a few fonts that support that. I've chosen Courier New for my application.
ForeColor
: LawnGreen in my example, or change it to any color you want.
ReadOnly
: True, I don't want to change the presented text, in any way.
ScrollBars
: I wanted this set None, but to get my scrolling working, it needs the scrollbar, so I set Both.
Size
and Location
: Drag around and resize in Design mode, or type the numbers.
We want to be able to view a .nfo file correctly in the richTextBox
. In Design mode, add a richTextBox
to the form. Change the Properties like the example above or to your own desire. If you don't have the Load
event from the Form
already, create one (e.g. Form1_Load). When the Form
and all components are loaded, we want to check if the .nfo file exists. When it does, convert it to the right format and present it, otherwise put the text 'NFO not found' in the richTextBox
.
Final code (this just shows the text in the box, no scrolling yet):
private void Form1_Load(object sender, EventArgs e)
{
string file_name = "C:\\Test\\DARTY.nfo";
if (System.IO.File.Exists(file_name) == true) {
System.Text.Encoding encoding = System.Text.Encoding.GetEncoding(437);
System.IO.StreamReader file = new System.IO.StreamReader(file_name, encoding);
richTextBox1.Text = file.ReadToEnd();
file.Close();
}
else {
richTextBox1.Text = "File not Found! :( --- Where is DARTY.nfo??";
}
}
OR we can use a .nfo file as a resource, which will be better in this case.
To do this, open the project properties and select the 'Resources' tab. Add an existing file (our .nfo file)
and view the properties. We need to change the FileType
to Text and then another option appears:
Encoding
. Set this to OEM United States - Codepage 437. If those options aren't available, try to change the View to 'View Details' instead of View In List or View As Thumbnails (Just like on computer).
When this is set, we don't have to check existence and don't have to read and encode the file anymore.
This will leave the following short code as final result:
string file_name = Properties.Resources.Eng_Dut_01; richTextBox1.Text = file_name;
The variable 'file_name' will be directed to the resource we've added and the Text
of the richTextBox
will be filled with the resource data. We don't need the lines from the previous part anymore to work through the file!
We want to be able to disable all interaction with the richTextBox
, without disabling the box itself. Disabling the richTextBox
is almost all right, but it prevents us from selecting custom colors!
I've created a new Form
with the same size and location as the richTextBox
. Opacity 1% so you can't see it and it moves around with the application as well. This prevents any interaction with our richTextBox
, just as we wanted!
If you want to see the code, use my source code (v1.3).
In v1.4 I've removed the Shield (Form
) that stayed on top of all other Windows Applications and I substituted it with blocking mouseclicks. It didn't work with the clickevents, but I've found great code samples online that worked:
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 0xA4 || m.Msg == 0xA5 || m.Msg == 0xA6) return true;
if (m.Msg == 0x204 || m.Msg == 0x205 || m.Msg == 0x206 || m.Msg == 0x207 || m.Msg == 0x208 || m.Msg == 0x209) return true;
return false;
}
Note that this applies to the whole active Form
. But as my Form
only accepts left mouse clicks, I don't care blocking the other mousebuttons for it.
We want to be able to autoscroll the richTextBox
and loop it, to view all the text like movie credits.
Prepare, as this code isn't easy at all. You don't have an option to just automatically scroll a box at a specified speed. There is a code option however to go up line by line, but that isn't easy to read. See it this way: We need a Messageservice from a dll, to tell the richTextBox
to move up a pixel each few milliseconds. So we set up the task (moving up) and have to create a timer, that sends the task as a message every few milliseconds we have set before.
I didn't get all of the code, but it worked! See REFERENCES at the bottom for the project I got this from. The only thing I changed was the speed of scrolling + options to adjust that, it goes back to start when it reaches the end (loop) and I changed the color before the text updates to a new location. This was hard as I needed to sync it with the different scrollingspeeds.
Import DLLs, create all references for the code
The following code (except first 'using' line) is placed between the public partial class
and public Form1( )
using System.Runtime.InteropServices;
public partial class Form1 : Form
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);
[DllImport("user32.dll")]
static extern int SetScrollInfo(IntPtr hwnd, int fnBar, [In] ref SCROLLINFO lpsi, bool fRedraw);
[DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
struct SCROLLINFO {
public uint cbSize;
public uint fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
enum ScrollBarDirection
{
SB_HORZ = 0,
SB_VERT = 1,
SB_CTL = 2,
SB_BOTH = 3
}
enum ScrollInfoMask
{
SIF_RANGE = 0x1,
SIF_PAGE = 0x2,
SIF_POS = 0x4,
SIF_DISABLENOSCROLL = 0x8,
SIF_TRACKPOS = 0x10,
SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS
}
const int WM_VSCROLL = 277;
const int SB_LINEUP = 0;
const int SB_LINEDOWN = 1;
const int SB_THUMBPOSITION = 4;
const int SB_THUMBTRACK = 5;
const int SB_TOP = 6;
const int SB_BOTTOM = 7;
const int SB_ENDSCROLL = 8;
private Timer t = new Timer();
Set the speed and enable Timer to send messages.
Add this code in the public Form1( )
public Form1()
{
InitializeComponent();
t.Interval = 40;
t.Tick += new EventHandler(t_Tick);
t.Enabled = true; }
Almost there, last bit of code for the autoscroll! Create the 2 methods t_Tick( )
and scroll( )
to run the process. I've added additional code to change the text while scrolling. This is in t_Tick( )
, it checks the current scrolling speed by getting the interval of the timer, which can be adjusted by pressing + and - .
Depending on the interval, I execute the correct colorchangespeedcode.
I added one method FastScrollpeed( )
(least code) as example, for rest see source code.
Depending on the interval, the color needs to be updated each pixel up or each few pixels up (in fast case). That's why I use int i to check the pixel number and reset on end to loop the color pattern.
int i = 1;
string ScrollEnabled = "true"; void t_Tick(object sender, EventArgs e) {
if (t.Interval == 80)
{ SlowScrollSpeed(); }
else if (t.Interval == 40)
{ CenterScrollSpeed(); }
else if (t.Interval == 10)
{ FastScrollSpeed(); }
if (ScrollEnabled == "true") { scroll(richTextBox1.Handle, 1); } else { scroll(richTextBox1.Handle, 0); }
}
void FastScrollSpeed() {
if (i >= 1 && i <= 6) { richTextBox1.ForeColor = Color.OrangeRed; i = i + 1; }
else if (i >= 7 && i <= 12) { richTextBox1.ForeColor = Color.DarkOrange; i = i + 1; }
else if (i >= 13 && i <= 18) { richTextBox1.ForeColor = Color.Yellow; i = i + 1; }
else if (i >= 19 && i <= 24) { richTextBox1.ForeColor = Color.LawnGreen; i = i + 1; }
else if (i >= 25 && i <= 30) { richTextBox1.ForeColor = Color.Turquoise; i = i + 1; }
else if (i >= 31 && i <= 36) { richTextBox1.ForeColor = Color.DodgerBlue; i = i + 1; }
else if (i >= 37 && i <= 42) { richTextBox1.ForeColor = Color.RoyalBlue; i = i + 1; }
else if (i >= 43 && i <= 48) { richTextBox1.ForeColor = Color.DarkViolet; i = i + 1; }
else if (i >= 49 && i <= 53) { richTextBox1.ForeColor = Color.HotPink; i = i + 1; }
else if (i == 54) { richTextBox1.ForeColor = Color.HotPink; i = 1; }
}
void scroll(IntPtr handle, int pixels)
{
IntPtr ptrLparam = new IntPtr(0);
IntPtr ptrWparam;
SCROLLINFO si = new SCROLLINFO();
si.cbSize = (uint)Marshal.SizeOf(si);
si.fMask = (uint)ScrollInfoMask.SIF_ALL;
GetScrollInfo(handle, (int)ScrollBarDirection.SB_VERT, ref si);
if (si.nPos < (si.nMax - si.nPage))
si.nPos += pixels;
else {
ptrWparam = new IntPtr(SB_ENDSCROLL); t.Enabled = false; SendMessage(handle, WM_VSCROLL, ptrWparam, ptrLparam);
}
SetScrollInfo(handle, (int)ScrollBarDirection.SB_VERT, ref si, true);
ptrWparam = new IntPtr(SB_THUMBTRACK + 0x10000 * si.nPos);
SendMessage(handle, WM_VSCROLL, ptrWparam, ptrLparam);
if (t.Enabled == false) {
SendMessage(handle, WM_VSCROLL, (IntPtr)SB_TOP, IntPtr.Zero);
t.Enabled = true; }
}
As we can't interact with the richTextBox
anyways, it would be great if we could move around the application by dragging the richTextBox
. I've found some code online that enabled moving the whole Form
by dragging a control on it:
private void richTextBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
dragging = true;
pointClicked = new Point(e.X, e.Y);
}
else
{ dragging = false; }
pictureBox1.Focus();
}
private void richTextBox1_MouseUp(object sender, MouseEventArgs e)
{
dragging = false;
pictureBox1.Focus();
}
private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
{
if (dragging)
{
Point pointMoveTo;
pointMoveTo = this.PointToScreen(new Point(e.X, e.Y));
pointMoveTo.Offset(-pointClicked.X, -pointClicked.Y);
this.Location = pointMoveTo;
}
}
This should be it, you should have automatic scrolling and looping text that you load from a .nfo text file (also in resource), convert and view in the richTextBox
, with optional color changing code. You can move the Form
around by dragging this control as well.
6) Another PICTUREBOX [Disabled]
Refer to 4) The Picturebox [Clickable] But don't add any (click)Event and set the Property Enabled
to False. This will do, without any code, you can drag around any disabled objects.
7) Buttons/KeyPress for Speed options [Pause, Slower, Faster] {Limited}
7.1) BUTTONS
: Add some buttons you want, change the Text
to P, - and + for the functions. For each Button
: add the Event Click
. Within these methods we put the actions to create this new functionality. I created these: buttonp (PAUSE), buttonmin (SLOWER) and buttonplus (FASTER).
Note the t.Interval
, which we've set in 'Set the speed and enable Timer to send messages'
from 5) The RICHTEXTBOX. The setting that I use as default speed is t.Interval = 40;
private void buttonplus_Click(object sender, EventArgs e)
{
if (t.Interval > 10) {
t.Interval = t.Interval - 15; if (t.Interval <= 10) { buttonplus.Enabled = false; } buttonmin.Enabled = true; }
}
private void buttonmin_Click(object sender, EventArgs e)
{
if (t.Interval < 70)
{
t.Interval = t.Interval + 15;
if (t.Interval >= 70)
{ buttonmin.Enabled = false; }
buttonplus.Enabled = true;
}
}
private void buttonp_Click(object sender, EventArgs e)
{
if (t.Enabled == true) {
t.Enabled = false; }
else {
t.Enabled = true; }
}
7.2) KEYPRESS
Event:
Determine where you want to have the ability to press your keyboard key. I decided my form was the best choice, but the focus just wan't there. I've used the following steps:
- I set the Form Propery
KeyPreview
= True;
- I changed the
TabIndex
from all the Buttons
to high(er) values;
- In the Form1.Designer.cs I added
this.Focus();
to the Form
, just to be sure.
Then, time for the KeyPress
Events. Go to the Form Properties and select the Event options. Add KeyPress
. For this one method, we can add all the keyboard keys we want.
If you want the old code with button option, check the v1.1 source release.
In v1.4 I used the following situation:
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 'm') {
if (checkBox2.CheckState == CheckState.Checked)
{ checkBox2.CheckState = CheckState.Unchecked; }
else { checkBox2.CheckState = CheckState.Checked; }
}
if (e.KeyChar == 'p') {
if (ScrollEnabled == "true")
{ ScrollEnabled = "false";}
else { ScrollEnabled = "true"; }
}
if (e.KeyChar == '=' || e.KeyChar == '+') { if (t.Interval == 40)
{ t.Interval = t.Interval - 30; }
else if (t.Interval == 80)
{ t.Interval = t.Interval - 40; }
}
if (e.KeyChar == '-') { if (t.Interval == 40) { t.Interval = t.Interval + 40; }
else if (t.Interval == 10) { t.Interval = t.Interval + 30; } }
}
8) Custom Icon (No Code)
Refer to the Form
Properties of 1) The FORM [MAINFRAME]. In this section you can add an Icon for the application IN RUNNING STATE.
The .exe file itself still has it's default window Icon. To change this to the same/another Icon, open the Solution Explorer. Rightclick the name of your project (almost top in bold) and open the Properties. If the tab isn't set on Application, select that tab. You'll find the option 'Icon and manifest', where you can browse for the same .ico file. When you save this, your .exe file will also contain your selected icon.
9) 'About' Window
A new Form
that opens when you click on the corresponding Question Mark PictureBox
.
When you hover over the box, the Question Mark will glow. I added those 2 pictures as resource.
The next block of code shows how that Question Mark works:
void buttonQ_MouseEnter(object sender, EventArgs e)
{ this.buttonQ.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.QMarkNeonGlow)); }
void buttonQ_MouseLeave(object sender, EventArgs e)
{ this.buttonQ.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.QMarkNeonLessGlow)); }
private void buttonQ_Click(object sender, EventArgs e)
{
f2.TopMost = false; Form f3 = new Form3(); f3.ShowDialog(); }
By using the MouseEnter
and MouseLeave
Events you can change the appearance of the picture when the mouse hovers over the PictureBox
. I have to disable the shield's TopMost, otherwise it will prevent users from closing the popup. When users click the richTextBox
, I make sure that the TopMost of the shield (f2) is activated. It's not the best solution, but I'm satisfied with it for now. To see the complete setup, the source is your friend!
10) Music (mod format)
I wanted to have small music files (at least compared to mp3), so I've chosen the mod format[.it/.xm/.s3m/.mod]. Those can be big too, but I just download tracks < 1MB, to keep my application small. There are no simple ways to code playing music, only when you want to run .mp3/.wav using WMP. I've chosen irrKlang modplayer BASS to play my mod music files. [For more info, click the modplayer link] It was hard to find out how this would work all by myself, but I succeeded. Steps I've done for irrKlang are stated below as reference:
In the extracted irrKlang folder:
- Copy the 'Include' folder to your project folder on the system.
- Copy the correct dotNET version dll to your project folder (in my case: irrKlang-1.4.0\bin\dotnet-4\irrKlang.NET4.dll and also ikpFlac.dll and ikpMP3.dll if you want to play MP3 files.
- Copy the .exp and .lib file from this folder 'irrKlang-1.4.0\lib\Win32-visualStudio' to your project.
In your Visual Studio Project, do the following: In the Solution Explorer, rightclick 'References' and select Add Reference... Select the Browse tab, search and select your .NET dll (irrKlang.NET4.dll in my case) and add it.
Add this line to the top of your project:
using IrrKlang;
Then we can go to the actual code that loads and plays our mod music file. Refer to the first point (view a .nfo file correctly) of 5) The RICHTEXTBOX. We've used the Form1_Load( )
method there to read and convert the .nfo file and display it when the Form
loads. The same thing we'll do with our music when the application starts. Paste the following line just before the Form1_Load( )
method:
IrrKlang.ISoundEngine engine = new IrrKlang.ISoundEngine();
The reason I use it before the Form
loads, is because I need this variable in more methods (also to pause it)! In the Form1_Load( )
method, we add the following line:
engine.Play2D("C:\\Test\\Xaser-Aeolus.it", true);
This means we play a file on the computer, so as long as I can't include it in the project, you have to send it with the application and make sure it copies/extracts to the correct folder. Otherwise the application runs, but without music and possibly NFO file from the same folder.
Steps I've done for BASS:
I'm able to play my music from resource now, so this is easier and always works.
Download the BASS and Bass.Net dlls and add the files to the project, or copy them from my source. In Solution Explorer, go to references and add Bass.Net.dll as a reference. Unless you add them to resource, you have to put them with the final .exe as well. When the dlls are added and the reference is made, add the following line to the top:
using Un4seen.Bass;
I have a directory 'Resources' in my project and rightclick -> added my mod music file. Set properties of it: Build Action
: Embedded Resource.
Using the following code in Form1_Load( )
I can play that track from resource using BASS on startup:
BassNet.Registration("xxxxxxxx@xxxxxxxx.xx", "XXXXXXXXXXXXXXX"); Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
using (var manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("WindowsFormsApplication1.Resources.Saga Musix - Heaven.it"))
{
if (manifestResourceStream != null)
{
int length = (int)manifestResourceStream.Length;
byte[] buffer = new byte[length];
manifestResourceStream.Read(buffer, 0, length);
int load = Bass.BASS_MusicLoad(buffer, 0, length, BASSFlag.BASS_SAMPLE_LOOP, 0);
Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_GVOL_MUSIC, vol);
Bass.BASS_ChannelPlay(load, false);
}
}
Refer to 3) The CHECKBOX [Pause Music] to see how to pause the running mod music and continue it.
11) Additional Settings
Here I place the things I've changed to let it appear nicely on other places on the computer.
Default .exe Filename: We go to the Solution Explorer and rightclick our project and then Properties. Select the 'Application' tab and change the Assembly Name to whatever you want for the exe.
As I'm in BETA, it doesn't really matter, I change it to character name to see a difference ('Angel').
If you set this, you don't have to change the name of the exe manually after you've debugged (exported) the .exe with the default 'TestApplication.exe' name.
Process Description: I noticed when running my program, that the description in Taskmanager is WindowsFormsApplication1? That's not what I want, I want something like (Argaï) NFO Viewer! To change the Process Description, go to the Solution Explorer, under YourProjectName you see the directory 'Properties'. In that directory, rightclick the AssemblyInfo.cs and click 'View Code'. [assembly: AssemblyTitle("WindowsFormsApplication1")], change the Title in what you want and it will show that title as the Description when your Process is running!
Taskbar and Taskmanager appearance: As informed before, changing the Property Text
of the Form
will create the 'program name' which appears when you hover over the running icon on the taskbar. The Assembly Name that is changed will present the .exe name that will be shown as process in Taskmanager.
Points of Interest
In just a few weeks I created this. The basic stuff was easy to do, but to make my richTextBox
autoscroll and the way I wanted it (looped) was hard, even as changing the colors with it. But also disabling all interaction with it, without disabling the richTextBox
itself was kind of hard to find out. I worked using trial and error and still do. Using some code samples from people online to achief this was really hard, as I always got errors of 'missing references' etc... I'm happy I got that all working now!
History
Changes after first upload:
Update 1.1:
General changes:
- Assembly Name changed;
- Process description changed [See 11) Additional Settings];
- Tabindex
of controls changed;
- Focus added to Form
(for general KeyPress
option);
Functionality:
- Added 3 buttons
for autoscroll speedoptions [See 7) Buttons/KeyPress];
- Added 3 KeyPress
options to do the same as the buttons [See 7) Buttons/KeyPress];
I prefer the keypress, but had to test with buttons first and fix the focus etc...
Update 1.2:
Functionality:
- Added the .NFO text file as a resource to the project so people don't need to extract it to specific location anymore. I still try to add the music and dll file as a resource as well. (See the 'use a .nfo file as a resource' part of 5) The RICHTEXTBOX);
BugFixes:
- Pressing arrow keys won't allow you to enter richTextBox
anymore. (See 1) The FORM);
Update 1.3:
General changes:
- Made Icon rounder (used circle shape instead of manual removing all around the circle);
- Better documented and ordened the Source Code for own reference;
Functionality:
- Changed ModPlayer 'irrKlang' to 'BASS', which supports all tracks that first didn't work and it uses lighter DLLs which make my application easier to run on more systems (See 'Steps I've done for BASS' of 10) Music (mod format);
- Removed the close button and added more KeyPresses (Escape to close application) (See move around of 1) The FORM);
- Added a fade effect when closing the application, this also fades the music with it to create a smooth closing (See Fade Effect of music and app of 1) The FORM);
- The Music is now Resource! NO need to put it all on C:\Test anymore, it runs and works everywhere (See 'Steps I've done for BASS' of 10) Music (mod format));
- Changed the default startlocation, now the application always starts in center of screen (See Properties of 1) The FORM);
- Added a questionmark button which opens a simple 'About Window'. This displays the options of the application. While this window is active, you can't interact with the application itself. If you close the application, the questionmarkbutton will be disabled while fading (See 9) 'About' Window);
- The richTextBox
now has changing color functionality. It remains same speed, even if you change scrollspeed or pause the scrolling. I added a rough pattern of strong colors (See Create the 2 methods t_Tick( )
and scroll( )
of 5) The RICHTEXTBOX);
- Finally I added both DLLs as resource. One can be read internally, the other one has to be written to disk. Now you can run my application anywhere without copying the DLLs with it (Refer to my source and the link about DLLs in the References at the bottom of this Article);
BugFixes:
- Added a new Form as 'Shield' which prevents interaction with the richTextBox. Now the clickbug of v1.1/1.2 is solved. It does however take the focus of the application away, so KeyPresses won't work untill you click the application again. The shield also remains on top of any other application you run, even if my app is in background! If there's another solution I'll look into that;
- Flickering application when dragging outside of the screen has been solved! (See Properties of 1) The FORM);
- 'Line Jumping Bug' fixed, text now remains on same position instead of jumping to last passed line while updating colors when users pause the scroller;
Update 1.4:
General changes:
- Better documented and ordened the Source Code for own reference;
- Changed Project Name, so all my different designs also have different names!
Functionality:
- Added KeyPress '+' so both Numeric and Alphabetic + work. (See
7.2) KEYPRESS
Event)
- Added KeyPress 'M' to Mute Music by Keyboard Key when Application is active. (
same as above)
- Added a ToolTip on the picture to show info about site you go to after click and on the questionmark button for info. (See
put ToolTips on PictureBox
of
4) The PICTUREBOX [Clickable])
- Added ability to move Form around by dragging richTextBox. (See
move around the application by dragging the richTextBox
of
5) The RICHTEXTBOX);
- Updated my
About Window:
[New Form with functions used in Main Form, see source for code]+ Now has an animated .GIF with text on it, Custom colored Border, ability to move by dragging, custom closebutton with same mouseover gloweffect as Questionmarkbutton.
+ Window isn't on top anymore (removed ShowDialog()), can be opened once and you can still interact with the Main Form.
+ As I made App interactive while About window is open,
I added code that closes About window when you activate close button of Main Form.
+ As it has a custom Border, the Application won't 'hang' anymore, as it would when you click and hold a normal Windows Form Border.
+ As ShowDialog was disabled, CenterParent as StartLocation didn't work anymore.
So I've added code to manually create the new CenterParent StartLocation function.
+ New Link in About Window to my Digital HobbiesForum;
+ FadeOut of About Window on Close.
BugFixes:
- Removed blocking Shield and substituted it with blocking mouseclick and force Focus. Now the application won't be on top even if it is in background! (See
disable all interaction with the richTextBox
of
5) The RICHTEXTBOX);
Files: Added the first result [Top of Page];
Added the
Source Code [Top of Page];
Update 1.1:- Updated Picture in Article;
- Added v1.1 TestApplication [Top of Page];
- Added v1.1
Source Code [Top of Page];
Update 1.3:- Updated Picture in Article;
- Added v1.3 TestApplication [Top of Page];
- Added v1.3
Source Code [Top of Page];
Update 1.4:- Updated Picture in Article;
- Added v1.4 TestApplication [Top of Page];
- Added v1.4
Source Code [Top of Page];
[After updating pictures I added link to older pictures for reference]
Bugs
- Windows 8 (always?) contains empty background of checkBox
and/or Close Button
.
- When the Application Renders (partially) outside of the screen, it is cut off when it doesn't fit on the resolution of screen. Way/option to fix this?
References
Link to original code for custom Form
without any Border
and default Buttons
:
http://www.codeproject.com/Articles/8056/Creating-Custom-Shaped-Windows-Forms-in-NET
Link to original autoscroll code which I used and changed:
http://www.codeproject.com/Articles/23363/Scrolling-a-Rich-Textbox-Automatically.
Link to my Question 'how to use .nfo as resource':
http://www.codeproject.com/Questions/519140/Usingplusaplus-NFO-plustextplusfileplusasplusresou
Link to the 'add DLL as resource' which I implemented partly:
http://www.codeproject.com/Articles/528178/Load-DLL-From-Embedded-Resource