I want to show a pixel in the screen.I use openTk in Vs2010.
this is my code in Windows form application:
private void glControl1_Load(object sender, EventArgs e)
{
OpenTK.Graphics.OpenGL.GL.ClearColor(Color.DeepSkyBlue);
OpenTK.Graphics.OpenGL.GL.Color3(Color.Black);
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
OpenTK.Graphics.OpenGL.GL.Clear(OpenTK.Graphics.OpenGL.ClearBufferMask.ColorBufferBit|OpenTK.Graphics.OpenGL.ClearBufferMask.DepthBufferBit);
OpenTK.Graphics.OpenGL.GL.MatrixMode(MatrixMode.Modelview);
OpenTK.Graphics.OpenGL.GL.LoadIdentity();
OpenTK.Graphics.OpenGL.GL.Begin(BeginMode.Points);
OpenTK.Graphics.OpenGL.GL.Vertex3(3,5,9);
OpenTK.Graphics.OpenGL.GL.End();
glControl1.SwapBuffers();
}
when I run my code I just see a Blue screen.I don't know what is wrong!!!
In order to display anything you will need to set the transformation matrices for projection. In your code you are not setting anything which means that the rendering will not have any idea on where to put your point.
I'd suggest looking into some basic tutorial for working with low-level OpenGL. Most of it should be applicable to your scenario.
Take a look at opentk glcontrol-based apps
using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System.Diagnostics;
namespace GLControlApp
{
public partial class Form1 : Form
{
bool loaded = false;
public Form1()
{
InitializeComponent();
}
Stopwatch sw = new Stopwatch(); // available to all event handlers
private void glControl1_Load(object sender, EventArgs e)
{
loaded = true;
GL.ClearColor(Color.SkyBlue); // Yey! .NET Colors can be used directly!
SetupViewport();
Application.Idle += Application_Idle; // press TAB twice after +=
sw.Start(); // start at application boot
}
void Application_Idle(object sender, EventArgs e)
{
double milliseconds = ComputeTimeSlice();
Accumulate(milliseconds);
Animate(milliseconds);
}
float rotation = 0;
private void Animate(double milliseconds)
{
float deltaRotation = (float)milliseconds / 20.0f;
rotation += deltaRotation;
glControl1.Invalidate();
}
double accumulator = 0;
int idleCounter = 0;
private void Accumulate(double milliseconds)
{
idleCounter++;
accumulator += milliseconds;
if (accumulator > 1000)
{
label1.Text = idleCounter.ToString();
accumulator -= 1000;
idleCounter = 0; // don't forget to reset the counter!
}
}
private double ComputeTimeSlice()
{
sw.Stop();
double timeslice = sw.Elapsed.TotalMilliseconds;
sw.Reset();
sw.Start();
return timeslice;
}
private void SetupViewport()
{
int w = glControl1.Width;
int h = glControl1.Height;
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0, w, 0, h, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
GL.Viewport(0, 0, w, h); // Use all of the glControl painting area
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
if (!loaded)
return;
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
GL.Translate(x, 0, 0);
if (glControl1.Focused)
GL.Color3(Color.Yellow);
else
GL.Color3(Color.Blue);
GL.Rotate(rotation, Vector3.UnitZ); // OpenTK has this nice Vector3 class!
GL.Begin(BeginMode.Triangles);
GL.Vertex2(10, 20);
GL.Vertex2(100, 20);
GL.Vertex2(100, 50);
GL.End();
glControl1.SwapBuffers();
}
int x = 0;
private void glControl1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space)
{
x++;
glControl1.Invalidate();
}
}
private void glControl1_Resize(object sender, EventArgs e)
{
SetupViewport();
glControl1.Invalidate();
}
}
}
Related
I have written a C# WinForms application. I want to get the data of the sound card in regular intervals. For this, I use the NAudio package. To check if I initialize the objects waveIn and WaveFormat with the correct values (SampleRate, number of channels, number of depth bits), I generated several audio tracks with Audacity. Among others, a square wave that can be heard for 2.5 seconds, then is silent for 2.5 seconds, etc. In the WaveIn_DataAvailable event handler, I paint a rectangle. I would expect it to turn red for 2.5 seconds, then turn black for 2.5 seconds. Unfortunately, the rectangle always flickers red and black when the audio is muted. So there is the problem that I can't test because at the moment of silence (it seems) there are everything but zeros in e.Buffer. Even at the moment of the sound, the rectangle is not ‘permanently’ red. Actually there is always flickering between red and black. What is the problem?
My soundcard is capable of 48 kHz, 24 bit. I don't know the number of channels. If channels refers to stereo or mono, then, of course, channel = 2.
using System;
using System.Windows.Forms;
using NAudio.Wave;
namespace Sound_Capture_Program
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
}
private int DeviceNumber = 0;
private WaveIn waveIn = null;
private void FormMain_Load(object sender, EventArgs e)
{
for (int i = 0; i < WaveIn.DeviceCount; i++)
{
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(i);
ComboboxDevices.Items.Add(deviceInfo.ProductName);
}
if (ComboboxDevices.Items.Count >= 2)
{
ComboboxDevices.SelectedIndex = 1;
}
}
private void Combobox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (ComboboxDevices.SelectedIndex != -1)
{
this.DeviceNumber = ComboboxDevices.SelectedIndex;
}
}
private void ButtonStart_Click(object sender, EventArgs e)
{
int sampleRate = int.Parse(Textbox_SR.Text);
waveIn = new WaveIn()
{
DeviceNumber = this.DeviceNumber,
WaveFormat = new WaveFormat(sampleRate, 24, 1)
};
waveIn.DataAvailable += WaveIn_DataAvailable;
waveIn.StartRecording();
ButtonStart.Enabled = false;
ButtonStop.Enabled = true;
}
private void ButtonStop_Click(object sender, EventArgs e)
{
waveIn.DataAvailable -= WaveIn_DataAvailable;
waveIn.StopRecording();
waveIn.Dispose();
ButtonStart.Enabled = true;
ButtonStop.Enabled = false;
}
private void WaveIn_DataAvailable(object sender, WaveInEventArgs e)
{
using (System.Drawing.Graphics g = this.CreateGraphics())
{
//byte redvalue = (byte)(((int)e.Buffer[0] + (int)e.Buffer[1] + (int)e.Buffer[2]) / 3);
System.Drawing.Color color = System.Drawing.Color.FromArgb(e.Buffer[0], 0, 0);
using (System.Drawing.SolidBrush Brush = new System.Drawing.SolidBrush(color))
{
g.FillRectangle(Brush, 250, 150, 20, 20);
}
}
}
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
if (waveIn != null)
{
waveIn.DataAvailable -= WaveIn_DataAvailable;
waveIn.StopRecording();
waveIn.Dispose();
}
}
}
}
Audacity
For my school I have to do a little project.
The aim of the project is to do a game which spawns different rectangles and you have to click them.
If you click them you recive points and the rectangle gets replaced with a new one.
And every timer tick the box gets bigger.
We have to use pictureboxes.
Now my question is:
How can I make a detection to indicate a picturebox which colides with the panel-border or with a other picture box.
The problem is, that the picboxes are getting duplicated.
So how can I solve this problem?
This is my code:
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BoxClicker
{
public partial class Form1 : Form
{
private Random rndColor = new Random();
private Random rndCreation = new Random();
public Form1()
{
InitializeComponent();
}
private void CreateBox()
{
PictureBox gamebox = new PictureBox();
gamebox.Size = new Size(20, 20);
gamebox.Location = new Point(rndCreation.Next(0, pnlSpiel.Width - 30), rndCreation.Next(0, pnlSpiel.Height - 30));
gamebox.BackColor = Color.FromArgb(rndCreation.Next(0, 255), rndCreation.Next(0, 255), rndCreation.Next(0, 255));
pnlSpiel.Controls.Add(gamebox);
gamebox.Click += pictureBox1_Click;
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < numValues.Value; i++)
{
CreateBox();
}
tmrResize.Start();
txtNotification.Text = "Klicke auf die erscheinenden Boxen um Punkte zu sammeln!";
btnStart.Visible = false;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void pictureBox1_Click(object sender, EventArgs e)
{
CreateBox();
PictureBox gamebox = sender as PictureBox;
int addPoints = gamebox.Width;
txtPoints.Text = (Convert.ToInt32(txtPoints.Text) + addPoints).ToString();
if ((Convert.ToInt32(txtBiggestBox.Text) < addPoints))
{
txtBiggestBox.Text = (Convert.ToString(addPoints));
}
pnlSpiel.Controls.Remove(sender as PictureBox);
}
private void button1_Click_1(object sender, EventArgs e)
{
if (tmrEasterEgg.Enabled)
{
tmrEasterEgg.Stop();
BackColor = Color.LightGray;
}
else
{
tmrEasterEgg.Start();
}
}
private void tmrEasterEgg_Tick(object sender, EventArgs e)
{
Color randomColor = Color.FromArgb(rndColor.Next(256), rndColor.Next(256), rndColor.Next(256));
BackColor = randomColor;
}
private void tmrResize_Tick(object sender, EventArgs e)
{
for (int i = 0; i < pnlSpiel.Controls.Count; i++)
{
PictureBox gamebox = pnlSpiel.Controls[i] as PictureBox;
gamebox.Size = new Size(gamebox.Size.Width + 1, gamebox.Size.Height + 1);
}
}
private void btnReset_Click(object sender, EventArgs e)
{
pnlSpiel.Controls.Clear();
txtNotification.Text = "Das Spiel wurde zurückgesetzt";
txtPoints.Text = "0";
btnStart.Visible = true;
}
}
}
You can have the collision detection in your CreateBox method. And decide whether to add the object or not in there.
Like this:
private void CreateBox()
{
Rectangle bounds = new Rectangle(rndCreation.Next(0, pnlSpiel.Width - 30),
rndCreation.Next(0, pnlSpiel.Height - 30),
20, 20);
bool pBDoIntersect = false;
foreach (Control picturebox in pnlSpiel.Controls)
{
if (bounds.IntersectsWith(picturebox.Bounds))
{
pBDoIntersect = true;
}
}
if (!pBDoIntersect)
{
PictureBox gamebox = new PictureBox();
gamebox.Size = new Size(bounds.Width, bounds.Height);
gamebox.Location = new Point(bounds.X, bounds.Y);
gamebox.BackColor = Color.FromArgb(rndCreation.Next(0, 255), rndCreation.Next(0, 255), rndCreation.Next(0, 255));
pnlSpiel.Controls.Add(PB);
gamebox.Click += pictureBox1_Click;
}
else
{
// spawn in another place?
}
}
I'm creating a simple bouncing ball application that uses a timer to bounce the ball of the sides of a picture box, the trouble i'm having with this is that it bounces fine off the bottom and right side of the picture box but doesn't bounce off the top or left side and i'm not sure why, the ball size is 30 if you wanted to know
The code for it is:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace Ball
{
public partial class Form1 : Form
{
int x = 200, y = 50; // start position of ball
int xmove = 10, ymove = 10; // amount of movement for each tick
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void pbxDisplay_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics; // get a graphics object
// draw a red ball, size 30, at x, y position
g.FillEllipse(Brushes.Red, x, y, 30, 30);
}
private void timer1_Tick(object sender, EventArgs e)
{
x += xmove; // add 10 to x and y positions
y += ymove;
if(y + 30 >= pbxDisplay.Height)
{
ymove = -ymove;
}
if (x + 30 >= pbxDisplay.Width)
{
xmove = -xmove;
}
if (x - 30 >= pbxDisplay.Width)
{
xmove = -xmove;
}
if (y - 30 >= pbxDisplay.Height)
{
ymove = -ymove;
}
Refresh(); // refresh the`screen .. calling Paint() again
}
private void btnQuit_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void btnStart_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private void btnStop_Click(object sender, EventArgs e)
{
timer1.Enabled= false;
}
}
}
If anyone can see what my problem is then please let me know, thanks alot!
Well your method for edge recognition is wrong. Top left corner point got coordinates [0,0]. So you should check left and top against zero. Not Width and Height.
So your code should look like:
private void timer1_Tick(object sender, EventArgs e)
{
x += xmove; // add 10 to x and y positions
y += ymove;
if(y + 30 >= pbxDisplay.Height)
{
ymove = -ymove;
}
if (x + 30 >= pbxDisplay.Width)
{
xmove = -xmove;
}
if (x - 30 <= 0)
{
xmove = -xmove;
}
if (y - 30 <= 0)
{
ymove = -ymove;
}
Refresh(); // refresh the`screen .. calling Paint() again
}
I'm closing my project clicking the form1 red x on the top right corner i'm getting the exception.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenPop;
using OpenPop.Pop3;
using OpenPop.Mime;
namespace Pop3_Emails
{
public partial class Form1 : Form
{
static OpenPop.Pop3.Pop3Client cc = new Pop3Client();
ProgressBarWithText pbt = new ProgressBarWithText();
public Form1()
{
InitializeComponent();
pbt.Size = new Size(216, 10);
pbt.Location = new Point(8, 312);
groupBox1.Controls.Add(pbt);
backgroundWorker1.RunWorkerAsync();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
OpenPop.Pop3.Pop3Client PopClient = new OpenPop.Pop3.Pop3Client();
PopClient.Connect("net.net", 110, false);
PopClient.Authenticate("meuser", "mepass",
OpenPop.Pop3.AuthenticationMethod.UsernameAndPassword);
int messageCount = PopClient.GetMessageCount();
List<OpenPop.Mime.Message> allMessages = new List<OpenPop.Mime.Message>(messageCount);
for (int i = messageCount; i > 0; i--)
{
allMessages.Add(PopClient.GetMessage(i));
int nProgress = (messageCount - i) * 100 / messageCount;
backgroundWorker1.ReportProgress(nProgress, PopClient.GetMessageCount().ToString() + " Number of downloaded messages" + i);
}
PopClient.Disconnect();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pbt.Value = e.ProgressPercentage;
pbt.Text = e.ProgressPercentage.ToString() + "%";
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
public class ProgressBarWithText : ProgressBar
{
const int WmPaint = 15;
SizeF TextSize;
PointF TextPos;
public ProgressBarWithText()
{
this.DoubleBuffered = true;
this.TextChanged += ProgressBarWithText_TextChanged;
this.SizeChanged += ProgressBarWithText_SizeChanged;
}
public override string Text
{
get { return base.Text; }
set { base.Text = value; }
}
void RecalcTextPos()
{
if (string.IsNullOrEmpty(base.Text))
return;
using (var graphics = Graphics.FromHwnd(this.Handle))
{
TextSize = graphics.MeasureString(base.Text, this.Font);
TextPos.X = (this.Width / 2) - (TextSize.Width / 2);
TextPos.Y = (this.Height / 2) - (TextSize.Height / 2);
}
}
void ProgressBarWithText_SizeChanged(object sender, EventArgs e)
{
RecalcTextPos();
}
void ProgressBarWithText_TextChanged(object sender, EventArgs e)
{
RecalcTextPos();
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WmPaint:
using (var graphics = Graphics.FromHwnd(Handle))
graphics.DrawString(base.Text, base.Font, Brushes.Black, TextPos.X, TextPos.Y);
break;
}
}
protected override CreateParams CreateParams
{
get
{
CreateParams result = base.CreateParams;
result.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
return result;
}
}
}
}
}
The exception is in the ProgressBarWithText class on the line:
var graphics = Graphics.FromHwnd(this.Handle)
Cannot access a disposed object
So i added now form1 closing event.
What should i put in the event ? What to stop and dispose ?
Easier to code than to explain. Also, haven't tested it, but it works in my head:
private bool closingForm = false;
// Note, this is "Closing" event handler, not "Close"
Form1_Closing(object sender, CancelEventArgs e)
{
if (!closingForm && MessageBox.Show("You sure?", "Form1", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
else if (backgroundWorker1.IsBusy)
{
e.Cancel = true;
closingForm = true;
if (!backgroundWorker1.CancellationPending)
backgroundWorker1.CancelAsync();
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (closingForm)
this.Close();
}
In backgroundWorker1_DoWork you have to check in the loop if backgroundWorker1.CancellationPending is true, and then set e.Cancel to true, and just return from the method.
Little explanation anyway. User initiates a close, so the form initiates a cancelling of the background thread. But actual finish comes later, and only then we also close the form, with care not to interfere with the Closing and Close events the second time around.
You can check if object is disposed already before using it
void RecalcTextPos()
{
if (this.IsDisposed == true)
return;
if (string.IsNullOrEmpty(base.Text))
return;
using (var graphics = Graphics.FromHwnd(this.Handle))
{
TextSize = graphics.MeasureString(base.Text, this.Font);
TextPos.X = (this.Width / 2) - (TextSize.Width / 2);
TextPos.Y = (this.Height / 2) - (TextSize.Height / 2);
}
}
So I've been putting this graphics transformation program together and suddenly some change I can't figure out has made the app unresponsive. The menus no longer function, and it's supposed to draw axes and a grid on one of the panels... nothing. Any ideas?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace Transformer
{
public partial class Transformer : Form
{
/* Initialize parameters */
private bool drawAxes = true;
private bool drawGrid = true;
private List<ObjectSettings> dispObjects = new List<ObjectSettings>();
/* Initialize form */
public Transformer()
{
InitializeComponent();
}
private void Transformer_Load(object sender, EventArgs e)
{
// Populate available objects listbox
string currentDir = Directory.GetCurrentDirectory();
string[] fileEntries = Directory.GetFiles(currentDir + #"\Objects");
foreach (string s in fileEntries) {
int start = s.LastIndexOf(#"\");
int end = s.LastIndexOf(#".");
availObjectsListBox.Items.Add(s.Substring(start + 1, end - start - 1));
} // end foreach
}
/* Paint graphics */
// Paint main form
private void Transformer_Paint(object sender, PaintEventArgs e)
{
}
// Paint graphics panel
private void splitContainer2_Panel1_Paint(object sender, PaintEventArgs e)
{
Rectangle r = splitContainer2.Panel1.ClientRectangle;
Graphics g = splitContainer2.Panel1.CreateGraphics();
Pen axisPen = new Pen(Color.Gray, 2.0f);
Pen gridPen = new Pen(Color.Gray, 1.0f);
g.Clear(Color.White);
if (drawAxes) {
g.DrawLine(axisPen, r.Left + 0.5f * r.Width, r.Top, r.Left + 0.5f * r.Width, r.Bottom);
g.DrawLine(axisPen, r.Left, r.Top + 0.5f * r.Height, r.Right, r.Top + 0.5f * r.Height);
}
if (drawGrid) {
// Vertical lines
int xVal = 0;
int xCenter = r.Width / 2;
g.DrawLine(gridPen, xCenter, r.Top, xCenter, r.Bottom);
for (int i = 0; i < 10; i++) {
xVal += r.Width / 20;
g.DrawLine(gridPen, xCenter + xVal, r.Top, xCenter + xVal, r.Bottom);
g.DrawLine(gridPen, xCenter - xVal, r.Top, xCenter - xVal, r.Bottom);
}
// Horizontal lines
int yVal = 0;
int yCenter = r.Height / 2;
g.DrawLine(gridPen, r.Left, yCenter, r.Right, yCenter);
for (int i = 0; i < 10; i++) {
yVal += r.Height / 20;
g.DrawLine(gridPen, r.Left, yCenter + yVal, r.Right, yCenter + yVal);
g.DrawLine(gridPen, r.Left, yCenter - yVal, r.Right, yCenter - yVal);
}
}
// foreach object in displayed objects
// keep list of displayed objects and their settings (make struct)
g.Dispose();
axisPen.Dispose();
gridPen.Dispose();
}
/* File menu */
private void saveImageToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Close();
}
/* Options menu */
private void axesOnoffToolStripMenuItem_Click(object sender, EventArgs e)
{
if (drawAxes == true)
drawAxes = false;
else
drawAxes = true;
}
private void gridOnoffToolStripMenuItem_Click(object sender, EventArgs e)
{
if (drawGrid == true)
drawGrid = false;
else
drawGrid = true;
}
/* Help menu */
private void helpToolStripMenuItem_Click(object sender, EventArgs e)
{
AboutBox dlg = new AboutBox();
dlg.ShowDialog();
}
/* Other stuff */
private void timer1_Tick(object sender, EventArgs e)
{
Invalidate();
}
// ">>" button
private void availToDispButton_Click(object sender, EventArgs e)
{
dispObjectsListBox.Items.Add(availObjectsListBox.SelectedItem);
}
// "<<" button
private void dispToAvailButton_Click(object sender, EventArgs e)
{
availObjectsListBox.Items.Add(dispObjectsListBox.SelectedItem);
dispObjectsListBox.Items.Remove(dispObjectsListBox.SelectedItem);
}
// Clear all button
private void clearAllButton_Click(object sender, EventArgs e)
{
}
// Update preview box
private void availObjectsListBox_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}
Thanks!
Try commenting out (separately) the "load" and "paint" code, see which is the problem.
If the problem is the paint... I wonder - rather than creating your own Graphics, use the one given to you? Namely, e.Graphics. Note that you didn't create this, so it isn't your job to Dispose() it (so don't do that). I would also cache the Pen etc in fields rather than create them each time. Note that if you do create a Pen (etc) in a method, then using is a better way to Dispose() it.
There is also a foreach comment in the paint code that suggests something has been removed - this may be relevant to the problem...
If this is happening when loading then obviously the amount of files in the directory could be causing the GUI thread to hang.
Other then that my quick look through only makes me think to check the bools you are using to control drawing and to make sure that the panel you are using the paint event for is actually visible.
You should also check that your timer is actually ticking, and check its interval.
I would also look at using the using statement, or at least a finally block for your dispose. But that isn't what your question is about.
Most of those are obvious and you might have already checked them all before posting here, but I thought I would put up something in case you had missed it. Hopefully I will get a chance to look through in more detail and spot something else.