using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace ElectricityBillCalculator
{
public partial class MainForm : Form
{
// 人员信息
private List<PersonMeter> persons;
private TextBox txtRate;
private TextBox txtTotalBill;
private ComboBox cmbPeopleCount;
private Button btnCalculate;
private Label lblResult;
private DataGridView dgvDetail;
private Panel personPanel;
private const double DEFAULT_TOTAL_BILL = 50.0;
private string[] allNames = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };
public MainForm()
{
InitializeComponent();
InitializePersons(4);
}
private void InitializeComponent()
{
this.Text = "电费计算器 - 合租电费分摊";
this.Size = new System.Drawing.Size(980, 900);
this.StartPosition = FormStartPosition.CenterScreen;
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.BackColor = Color.WhiteSmoke;
// 标题
Label lblTitle = new Label();
lblTitle.Text = "📊 合租电费分摊系统";
lblTitle.Location = new System.Drawing.Point(20, 15);
lblTitle.Size = new System.Drawing.Size(930, 35);
lblTitle.Font = new System.Drawing.Font("微软雅黑", 16, System.Drawing.FontStyle.Bold);
lblTitle.ForeColor = Color.FromArgb(52, 73, 94);
this.Controls.Add(lblTitle);
// 人员面板
personPanel = new Panel();
personPanel.Location = new System.Drawing.Point(20, 60);
personPanel.Size = new System.Drawing.Size(930, 380);
personPanel.AutoScroll = true;
personPanel.BackColor = Color.White;
personPanel.BorderStyle = BorderStyle.FixedSingle;
this.Controls.Add(personPanel);
// 底部控制区
int yBase = 460;
// 第一行:电价、总电费、分摊人数和计算按钮
// 电价
Label lblRate = new Label();
lblRate.Text = "电 价:";
lblRate.Location = new System.Drawing.Point(30, yBase);
lblRate.Size = new System.Drawing.Size(60, 30);
lblRate.Font = new System.Drawing.Font("微软雅黑", 11, System.Drawing.FontStyle.Bold);
lblRate.ForeColor = Color.FromArgb(41, 128, 185);
this.Controls.Add(lblRate);
txtRate = new TextBox();
txtRate.Text = "0.5469";
txtRate.Location = new System.Drawing.Point(95, yBase);
txtRate.Size = new System.Drawing.Size(80, 30);
txtRate.Font = new System.Drawing.Font("微软雅黑", 10);
this.Controls.Add(txtRate);
Label lblRateUnit = new Label();
lblRateUnit.Text = "元/度";
lblRateUnit.Location = new System.Drawing.Point(180, yBase);
lblRateUnit.Size = new System.Drawing.Size(50, 30);
lblRateUnit.Font = new System.Drawing.Font("微软雅黑", 10);
this.Controls.Add(lblRateUnit);
// 总电费
Label lblTotalBill = new Label();
lblTotalBill.Text = "💡 总电费:";
lblTotalBill.Location = new System.Drawing.Point(240, yBase);
lblTotalBill.Size = new System.Drawing.Size(85, 30);
lblTotalBill.Font = new System.Drawing.Font("微软雅黑", 11, System.Drawing.FontStyle.Bold);
lblTotalBill.ForeColor = Color.FromArgb(231, 76, 60);
this.Controls.Add(lblTotalBill);
txtTotalBill = new TextBox();
txtTotalBill.Text = "50.00";
txtTotalBill.Location = new System.Drawing.Point(330, yBase);
txtTotalBill.Size = new System.Drawing.Size(80, 30);
txtTotalBill.Font = new System.Drawing.Font("微软雅黑", 10);
this.Controls.Add(txtTotalBill);
Label lblBillUnit = new Label();
lblBillUnit.Text = "元";
lblBillUnit.Location = new System.Drawing.Point(415, yBase);
lblBillUnit.Size = new System.Drawing.Size(30, 30);
lblBillUnit.Font = new System.Drawing.Font("微软雅黑", 10);
this.Controls.Add(lblBillUnit);
// 分摊人数
Label lblPeopleCount = new Label();
lblPeopleCount.Text = "👥 分摊人数:";
lblPeopleCount.Location = new System.Drawing.Point(455, yBase);
lblPeopleCount.Size = new System.Drawing.Size(95, 30);
lblPeopleCount.Font = new System.Drawing.Font("微软雅黑", 11, System.Drawing.FontStyle.Bold);
lblPeopleCount.ForeColor = Color.FromArgb(142, 68, 173);
this.Controls.Add(lblPeopleCount);
cmbPeopleCount = new ComboBox();
cmbPeopleCount.Location = new System.Drawing.Point(555, yBase);
cmbPeopleCount.Size = new System.Drawing.Size(65, 30);
cmbPeopleCount.Font = new System.Drawing.Font("微软雅黑", 10);
cmbPeopleCount.DropDownStyle = ComboBoxStyle.DropDownList;
cmbPeopleCount.Items.AddRange(new object[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" });
cmbPeopleCount.SelectedIndex = 3;
cmbPeopleCount.SelectedIndexChanged += CmbPeopleCount_SelectedIndexChanged;
this.Controls.Add(cmbPeopleCount);
// 计算按钮
btnCalculate = new Button();
btnCalculate.Text = "🧮 计算电费";
btnCalculate.Location = new System.Drawing.Point(660, yBase - 5);
btnCalculate.Size = new System.Drawing.Size(150, 40);
btnCalculate.Font = new System.Drawing.Font("微软雅黑", 11, System.Drawing.FontStyle.Bold);
btnCalculate.BackColor = Color.FromArgb(52, 152, 219);
btnCalculate.ForeColor = Color.White;
btnCalculate.FlatStyle = FlatStyle.Flat;
btnCalculate.FlatAppearance.BorderSize = 0;
btnCalculate.Click += BtnCalculate_Click;
this.Controls.Add(btnCalculate);
// 说明标签
Label lblHint = new Label();
lblHint.Text = "📌 用电量>0的人需承担单独计费,用电量=0的人仅平摊日常用电";
lblHint.Location = new System.Drawing.Point(30, yBase + 50);
lblHint.Size = new System.Drawing.Size(500, 25);
lblHint.Font = new System.Drawing.Font("微软雅黑", 9);
lblHint.ForeColor = Color.FromArgb(52, 73, 94);
this.Controls.Add(lblHint);
// 结果显示
lblResult = new Label();
lblResult.Text = "💰 每人应付:";
lblResult.Location = new System.Drawing.Point(20, yBase + 90);
lblResult.Size = new System.Drawing.Size(930, 35);
lblResult.Font = new System.Drawing.Font("微软雅黑", 14, System.Drawing.FontStyle.Bold);
lblResult.ForeColor = Color.FromArgb(39, 174, 96);
this.Controls.Add(lblResult);
// 明细表格
dgvDetail = new DataGridView();
dgvDetail.Location = new System.Drawing.Point(20, yBase + 135);
dgvDetail.Size = new System.Drawing.Size(930, 205);
dgvDetail.BackgroundColor = Color.White;
dgvDetail.BorderStyle = BorderStyle.FixedSingle;
dgvDetail.RowHeadersVisible = false;
dgvDetail.AllowUserToAddRows = false;
dgvDetail.AllowUserToDeleteRows = false;
dgvDetail.ReadOnly = true;
dgvDetail.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
dgvDetail.Font = new System.Drawing.Font("微软雅黑", 10);
dgvDetail.RowTemplate.Height = 38;
dgvDetail.ColumnHeadersHeight = 40;
dgvDetail.ColumnHeadersDefaultCellStyle.Font = new System.Drawing.Font("微软雅黑", 10.5f, System.Drawing.FontStyle.Bold);
dgvDetail.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
dgvDetail.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
dgvDetail.GridColor = Color.FromArgb(220, 220, 220);
dgvDetail.ScrollBars = ScrollBars.Vertical;
// 创建列
DataGridViewTextBoxColumn colName = new DataGridViewTextBoxColumn();
colName.Name = "姓名";
colName.HeaderText = "姓名";
colName.Width = 70;
colName.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
colName.FillWeight = 8;
DataGridViewTextBoxColumn colUsage = new DataGridViewTextBoxColumn();
colUsage.Name = "用电量";
colUsage.HeaderText = "用电量(度)";
colUsage.Width = 110;
colUsage.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
colUsage.DefaultCellStyle.Format = "F2";
colUsage.FillWeight = 12;
DataGridViewTextBoxColumn colSeparate = new DataGridViewTextBoxColumn();
colSeparate.Name = "单独计费";
colSeparate.HeaderText = "单独计费(元)";
colSeparate.Width = 120;
colSeparate.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
colSeparate.DefaultCellStyle.Format = "F4";
colSeparate.FillWeight = 13;
DataGridViewTextBoxColumn colDaily = new DataGridViewTextBoxColumn();
colDaily.Name = "日常平摊";
colDaily.HeaderText = "日常平摊(元)";
colDaily.Width = 120;
colDaily.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
colDaily.DefaultCellStyle.Format = "F4";
colDaily.FillWeight = 13;
DataGridViewTextBoxColumn colTotal = new DataGridViewTextBoxColumn();
colTotal.Name = "合计应付";
colTotal.HeaderText = "合计应付(元)";
colTotal.Width = 120;
colTotal.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
colTotal.DefaultCellStyle.Format = "F4";
colTotal.DefaultCellStyle.Font = new System.Drawing.Font("微软雅黑", 10.5f, System.Drawing.FontStyle.Bold);
colTotal.DefaultCellStyle.ForeColor = Color.FromArgb(231, 76, 60);
colTotal.FillWeight = 13;
DataGridViewTextBoxColumn colFormula = new DataGridViewTextBoxColumn();
colFormula.Name = "计算公式";
colFormula.HeaderText = "计算公式";
colFormula.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft; // 左对齐,方便阅读公式
colFormula.DefaultCellStyle.Font = new System.Drawing.Font("Consolas", 9.5f); // 稍微减小字体以适应
colFormula.DefaultCellStyle.ForeColor = Color.FromArgb(0, 0, 139);
colFormula.FillWeight = 41;
dgvDetail.Columns.Add(colName);
dgvDetail.Columns.Add(colUsage);
dgvDetail.Columns.Add(colSeparate);
dgvDetail.Columns.Add(colDaily);
dgvDetail.Columns.Add(colTotal);
dgvDetail.Columns.Add(colFormula);
// 设置列头颜色
dgvDetail.EnableHeadersVisualStyles = false;
dgvDetail.ColumnHeadersDefaultCellStyle.BackColor = Color.FromArgb(52, 73, 94);
dgvDetail.ColumnHeadersDefaultCellStyle.ForeColor = Color.White;
dgvDetail.ColumnHeadersDefaultCellStyle.SelectionBackColor = Color.FromArgb(52, 73, 94);
this.Controls.Add(dgvDetail);
}
private void InitializePersons(int count)
{
personPanel.Controls.Clear();
persons = new List<PersonMeter>();
int x = 20, y = 25;
for (int i = 0; i < count && i < allNames.Length; i++)
{
string name = allNames[i];
var person = new PersonMeter(name);
persons.Add(person);
// 创建人员卡片
GroupBox groupBox = new GroupBox();
groupBox.Text = $"👤 {name}";
groupBox.Location = new System.Drawing.Point(x, y);
groupBox.Size = new System.Drawing.Size(430, 165);
groupBox.Font = new System.Drawing.Font("微软雅黑", 10, System.Drawing.FontStyle.Bold);
this.personPanel.Controls.Add(groupBox);
// 起始表底
Label lblStart = new Label();
lblStart.Text = "起始表底:";
lblStart.Location = new System.Drawing.Point(15, 40);
lblStart.Size = new System.Drawing.Size(80, 25);
lblStart.Font = new System.Drawing.Font("微软雅黑", 9);
groupBox.Controls.Add(lblStart);
TextBox txtStart = new TextBox();
txtStart.Name = $"txtStart_{name}";
txtStart.Location = new System.Drawing.Point(100, 38);
txtStart.Size = new System.Drawing.Size(305, 25);
txtStart.Font = new System.Drawing.Font("微软雅黑", 9);
txtStart.Text = "0";
groupBox.Controls.Add(txtStart);
person.TxtStart = txtStart;
// 结束表底
Label lblEnd = new Label();
lblEnd.Text = "结束表底:";
lblEnd.Location = new System.Drawing.Point(15, 75);
lblEnd.Size = new System.Drawing.Size(80, 25);
lblEnd.Font = new System.Drawing.Font("微软雅黑", 9);
groupBox.Controls.Add(lblEnd);
TextBox txtEnd = new TextBox();
txtEnd.Name = $"txtEnd_{name}";
txtEnd.Location = new System.Drawing.Point(100, 73);
txtEnd.Size = new System.Drawing.Size(305, 25);
txtEnd.Font = new System.Drawing.Font("微软雅黑", 9);
txtEnd.Text = "0";
groupBox.Controls.Add(txtEnd);
person.TxtEnd = txtEnd;
// 用电量显示
Label lblUsage = new Label();
lblUsage.Text = "用电量:0.00 度";
lblUsage.Name = $"lblUsage_{name}";
lblUsage.Location = new System.Drawing.Point(15, 115);
lblUsage.Size = new System.Drawing.Size(390, 30);
lblUsage.Font = new System.Drawing.Font("微软雅黑", 10, System.Drawing.FontStyle.Regular);
lblUsage.ForeColor = Color.FromArgb(44, 62, 80);
groupBox.Controls.Add(lblUsage);
person.LblUsage = lblUsage;
// 布局:每行2个
x += 450;
if (x >= 910)
{
x = 20;
y += 180;
}
}
}
private void CmbPeopleCount_SelectedIndexChanged(object sender, EventArgs e)
{
if (cmbPeopleCount.SelectedItem != null)
{
int count = Convert.ToInt32(cmbPeopleCount.SelectedItem.ToString());
InitializePersons(count);
}
}
private void BtnCalculate_Click(object sender, EventArgs e)
{
try
{
double rate = GetDouble(txtRate.Text);
if (rate <= 0)
{
MessageBox.Show("请输入有效的电价!", "输入错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
double totalCost = GetDouble(txtTotalBill.Text);
if (totalCost <= 0)
{
MessageBox.Show("请输入有效的总电费!", "输入错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// 读取每个人的表底数据
List<PersonData> dataList = new List<PersonData>();
int totalPeople = 0;
foreach (var person in persons)
{
double start = GetDouble(person.TxtStart.Text);
double end = GetDouble(person.TxtEnd.Text);
if (end < start)
{
MessageBox.Show($"{person.Name} 的结束表底不能小于起始表底!", "输入错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
double usage = end - start;
totalPeople++;
bool isSeparateBilling = usage > 0;
dataList.Add(new PersonData
{
Name = person.Name,
Start = start,
End = end,
Usage = usage,
IsCooking = isSeparateBilling
});
string billingStatus = isSeparateBilling ? "⚡ 单独计费" : "仅平摊";
person.LblUsage.Text = $"用电量:{usage:F2} 度 ({billingStatus})";
}
if (totalPeople == 0)
{
MessageBox.Show("没有人员数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 计算每个人的单独计费
double totalSeparateBillingCost = 0;
List<string> separateCostDetails = new List<string>(); // 存储每个单独计费的详细信息
foreach (var data in dataList)
{
if (data.IsCooking)
{
data.CookingCost = data.Usage * rate;
totalSeparateBillingCost += data.CookingCost;
separateCostDetails.Add($"{data.CookingCost:F4}");
}
else
{
data.CookingCost = 0;
}
}
// 构建所有单独计费的表达式
string allSeparateCostsStr = string.Join("+", separateCostDetails);
if (string.IsNullOrEmpty(allSeparateCostsStr))
{
allSeparateCostsStr = "0.0000";
}
// 日常用电费用 = 总电费 - 所有单独计费
double dailyElectricCost = totalCost - totalSeparateBillingCost;
// 如果日常用电费用为负数,提示用户
if (dailyElectricCost < 0)
{
MessageBox.Show($"单独计费总计 {totalSeparateBillingCost:F2} 元已超过总电费 {totalCost:F2} 元!\n请检查电表读数或电价是否正确。",
"费用超支", MessageBoxButtons.OK, MessageBoxIcon.Warning);
dailyElectricCost = 0;
}
// 日常用电平摊给所有人
double perPersonDaily = dailyElectricCost / totalPeople;
// 计算每个人最终应付
foreach (var data in dataList)
{
data.TotalCost = data.CookingCost + perPersonDaily;
}
// 清空表格
dgvDetail.Rows.Clear();
// 填充表格
foreach (var data in dataList)
{
string formula;
if (data.IsCooking)
{
// 有单独计费的人:显示完整计算过程
// 格式:(总电费 - (所有单独计费之和)) ÷ 总人数 + 自己的单独计费
formula = $"({totalCost:F2} - ({allSeparateCostsStr})) ÷ {totalPeople} + {data.CookingCost:F4}";
}
else
{
// 没有单独计费的人:仅日常平摊
// 格式:(总电费 - (所有单独计费之和)) ÷ 总人数
formula = $"({totalCost:F2} - ({allSeparateCostsStr})) ÷ {totalPeople}";
}
dgvDetail.Rows.Add(
data.Name,
data.Usage,
data.CookingCost,
perPersonDaily,
data.TotalCost,
formula
);
}
// 突出显示每人应付总额
string summary = "💰 每人应付:";
foreach (var data in dataList)
{
summary += $"{data.Name} {data.TotalCost:F2}元 ";
}
lblResult.Text = summary;
}
catch (Exception ex)
{
MessageBox.Show($"计算出错:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private double GetDouble(string text)
{
if (string.IsNullOrWhiteSpace(text))
return 0;
return Convert.ToDouble(text);
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
// 人员电表类
public class PersonMeter
{
public string Name { get; set; }
public TextBox TxtStart { get; set; }
public TextBox TxtEnd { get; set; }
public Label LblUsage { get; set; }
public PersonMeter(string name)
{
Name = name;
}
}
// 人员数据类
public class PersonData
{
public string Name { get; set; }
public double Start { get; set; }
public double End { get; set; }
public double Usage { get; set; }
public bool IsCooking { get; set; }
public double CookingCost { get; set; }
public double TotalCost { get; set; }
}
}