[英]Trying to figure out how to dynamically change which array is used for a label based on combo box selection?
所以不幸的是,我现在有点超级菜鸟哈哈所以如果可能的话请多多包涵。
我试图制作的程序是一个钢琴音符随机发生器,用于有效地记忆音符/音阶。 我认为这将是一个有趣的小程序,可以帮助我的钢琴之旅和编程之旅哈哈。
所以在这个程序中,我放了一个组合框,每个钢琴音阶都有一个选项,如下所示:
然后我继续为每个音阶和该音阶的音符制作一个数组,如下所示:
//Arrays to store each scale
string[] cMajor = { "C", "D", "E", "F", "G", "A", "B", "C", };
string[] dMajor = { "D", "E", "F#", "G", "A", "B", "C#", "D", };
string[] eMajor = { "E", "F#", "G#", "A", "B", "C#", "D#", "E", };
string[] fMajor = { "F", "G", "A", "Bb", "C", "D", "E", "F", };
string[] gMajor = { "G", "A", "B", "C", "D", "E", "F#", "G", };
然后我使用一个随机数生成器作为 arrays 的索引,这样它会随机 select 一个介于 0 和 7 之间的数字,理想情况下 select 是一个随机数组索引,然后我们可以将其传递到 label 这将是钢琴音符显示在屏幕上。
//Number Generator to pass into the newNumber variable which will act as an index for the array
Random generator = new Random();
int newNumber = generator.Next(0, 7); // Generating a number that equates to the number of notes in a particular scale
然后我输入代码来检查所选输入的 combobox,然后根据所选的比例创建 label:
if (comboBox1.SelectedIndex == 0)
{
OUTPUTLABEL1.Font = new Font("Segoe UI", 100);
OUTPUTLABEL1.Location = new Point(80, 5);
OUTPUTLABEL1.Text = cMajor[newNumber];
}
在大多数情况下,一切都按预期工作。 我可以在屏幕上弹出 select 比例和注释,问题是其中没有一个是动态的,哈哈。 如您所见,比例选择被硬编码到程序中。 cMajor 的规模也是硬编码的。
我的想法是,我可以从 ComboBox 中选择一个比例尺 select,并且文本会根据在 ComboBox 中选择的比例尺动态变化。我能想到的唯一实现这一点的方法会产生大量多余的 if 语句,我觉得就像我可能有更好的方法来完成这个。
非常感谢你们,如果这是显而易见的或我可能犯的任何其他错误,我再次道歉。 这是我在这里的第一篇文章,我希望我已经为你们提供了足够的信息! 再次感谢你!
完整代码(忽略计时器):
public void RandomizeButton_Click(object sender, EventArgs e)
{
//Arrays to store each scale
string[] cMajor = { "C", "D", "E", "F", "G", "A", "B", "C", };
string[] dMajor = { "D", "E", "F#", "G", "A", "B", "C#", "D", };
string[] eMajor = { "E", "F#", "G#", "A", "B", "C#", "D#", "E", };
string[] fMajor = { "F", "G", "A", "Bb", "C", "D", "E", "F", };
string[] gMajor = { "G", "A", "B", "C", "D", "E", "F#", "G", };
//Number Generator to pass into the newNumber variable which will act as an index for the array
Random generator = new Random();
int newNumber = generator.Next(0, 7); // Generating a number that equates to the number of notes in a particular scale
if (comboBox1.SelectedIndex == 0)
{
OUTPUTLABEL1.Font = new Font("Segoe UI", 100);
OUTPUTLABEL1.Location = new Point(80, 5);
OUTPUTLABEL1.Text = cMajor[newNumber];
}
if (TimerCheckbox.Checked)
{
seconds = int.Parse(timeInterval.Text);
timer1.Start();
}
}
如果我对 arrays 和组合框的思考方式不太理想,那么如果需要,我愿意接受一个全新的解决方案! 非常感谢你们!
看起来你想要一个链接的数据结构。 在一个变量和另一个变量之间设置 map 的最常见方法是使用字典
//you can use a dictionary
public Dictionary<string, string[]> scalesDict = new Dictionary<string, string[]>() {
{"a", new string[] { "C", "D", "E", "F", "G", "A", "B", "C", } },
{"b", new string[] { "D", "E", "F#", "G", "A", "B", "C#", "D", } },
{"c", new string[] { "E", "F#", "G#", "A", "B", "C#", "D#", "E", } },
{"d", new string[] { "F", "G", "A", "Bb", "C", "D", "E", "F", } },
{"e", new string[] { "G", "A", "B", "C", "D", "E", "F#", "G", } } };
private string[] GetScale(string comboBoxValue) {
return scalesDict[comboBoxValue];
}
上面的代码将根据 combobox 值为您提供数组(将 a、b、c、d 和 e 替换为 combobox 使用的任何值)
字典是非常强大的工具 c#
不过你的问题有点含糊,所以我不确定我是否已经完全解决了你的问题,请告诉我
您的问题和代码涵盖了几个相关领域:
Random
class实现Randomize function。好吧,你确实说过如果需要的话我愿意接受一个全新的解决方案! 所以这个答案将探讨关于这三件事的其他方法 go 并为您提供一些新技能来尝试。 特别是,如果您尽早了解如何使用数据绑定(如本示例所示),它可能会加速您在 WinForms 中所做的其他所有事情。
将秤绑定到 ComboBox
一种方法是定义一个class
来表示一个 Scale。 这比字典查找更紧密地关联信息。 ToString
方法将确定组合框中显示的内容。
enum ScaleForm { Major, Minor }
enum Key { A, B, C, D, E, F, G }
enum Signature { Natural, [Description("\u266F")] Sharp, [Description("\u266D")] Flat }
class Scale
{
public Key Key{ get; set; }
public ScaleForm Form { get; set; }
public Signature Signature { get; set; }
public string[] Notes { get; set; } = new string[0];
// Determines what displays in the ComboBox
public override string ToString()=> $"{Key}{Signature.ToUnicode()} {Form}";
}
static class Extensions
{
public static string ToUnicode(this Signature signature)
{
switch (signature)
{
default: return string.Empty;
case Signature.Sharp: return "\u266F";
case Signature.Flat: return "\u266D";
}
}
}
接下来制作一个Scale
对象列表,它将成为组合框的动态源:
BindingList<Scale> Scales = new BindingList<Scale>();
在加载主窗体的方法中初始化各个比例尺和比例尺列表。
public partial class MainForm : Form
{
public MainForm() => InitializeComponent();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Scales.Add(new Scale
{
Key = Key.C,
Notes = new[] { "C", "D", "E", "F", "G", "A", "B", "C", },
});
Scales.Add(new Scale
{
Key = Key.D,
Notes = new[]
{
"D", "E",
$"F{Signature.Sharp.ToUnicode()}",
"G", "A", "B",
$"C{Signature.Sharp.ToUnicode()}",
"D",
},
});
Scales.Add(new Scale
{
Key = Key.E,
Notes = new[]
{
"E",
$"F{Signature.Sharp.ToUnicode()}",
$"G{Signature.Sharp.ToUnicode()}",
"A", "B",
$"C{Signature.Sharp.ToUnicode()}",
$"D{Signature.Sharp.ToUnicode()}",
"E",
},
});
Scales.Add(new Scale
{
Key = Key.F,
Notes = new[]
{
"F", "G", "A",
$"B{Signature.Flat.ToUnicode()}",
"C", "D", "E", "F",
},
});
Scales.Add(new Scale
{
Key = Key.G,
Notes = new[]
{
"G", "A", "B", "C", "D", "E",
$"F{Signature.Sharp.ToUnicode()}",
"G",
},
});
Scales.Add(new Scale
{
Key = Key.B, Signature = Signature.Flat,
Notes = new[] {
$"B{Signature.Flat.ToUnicode()}",
"C", "D",
$"E{Signature.Flat.ToUnicode()}",
"F", "G", "A",
$"B{Signature.Flat.ToUnicode()}"},
});
comboBoxScales.TabStop= false;
comboBoxScales.DropDownStyle= ComboBoxStyle.DropDownList;
// Attach the list of scales
comboBoxScales.DataSource= Scales;
// Initialize the value
onScaleSelectionChanged(this, EventArgs.Empty);
// Respond to combo box changes
comboBoxScales.SelectedIndexChanged += onScaleSelectionChanged;
// Respond to click randomize
buttonRandomize.Click += onClickRandomize;
// Respond to automated timer checkbox changes
checkBoxTimer.CheckedChanged += onTimerCheckedChanged;
}
.
.
.
}
同样在同一方法中,附加了事件处理程序。 例如,当在组合框中选择新比例时,首先发生的事情是将 label 设置为根。
private void onScaleSelectionChanged(object? sender, EventArgs e)
{
labelCurrentNote.Text =
((Scale)comboBoxScales.SelectedItem).Notes[0];
}
使用Random
class
您只需要一个Random
实例。 为了进行测试,您每次都可以生成相同的伪随机数字序列,方法是用一个 int 作为种子,例如new Random(1)
。 但如此处所示,每次运行时,种子都是从系统时钟派生的,用于不同的序列。
private readonly Random _rando = new Random();
private void onClickRandomize(object? sender, EventArgs e) =>
execNextRandom(sender, e);
一种实现方式是获取介于 0 和 7 之间的数字,并使用它从组合框中的当前选择中取消对数组值的引用。 这也使得在每次点击时得到一个新的注释很重要,这样用户在点击时就会感到自信。
private void execNextRandom(object? sender, EventArgs e)
{
string preview;
do
{
// Randomize, but do not repeat because it makes
// it seem like the button doesn't work!
preview =
((Scale)comboBoxScales.SelectedItem)
.Notes[_rando.Next(0, 8)]; // Will never return 8!
} while (preview.Equals(labelCurrentNote.Text));
labelCurrentNote.Text = preview;
}
自动定时器
获得重复 function 的一种更简单的方法是为计时器复选框创建一个异步处理程序。 无需启动和停止计时器或以这种方式处理事件,但它仍然提供了通过“不”阻塞线程来保持 UI 响应的优势,除非获取了新的随机笔记。
private async void onTimerCheckedChanged(object? sender, EventArgs e)
{
while(checkBoxTimer.Checked)
{
execNextRandom(sender, e);
await Task.Delay(TimeSpan.FromSeconds((double)numericUpDownSeconds.Value));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.